I am buinding a chat for an application, so when a user logs in I need to send them all 'unseen' messages, I am using entityframework, Id like to return only the last 20 unseen messages. but my query is not working, currently I get this exception
Count must be a DbConstantExpression or a DbParameterReferenceExpression
what am I doing wrong?
List<ChatVM> unSeenChats = db.Chats.Where(chat => !chat.Seen)
.Select(chat => new ChatVM
{
Id = chat.Id,
IsAnnonymous = chat.IsAnnonymous,
UserName = chat.UserName,
Messages = chat.Messages
.OrderBy(x => x.DateTime)
.Skip(chat.Messages.Count - 20 > 0
? chat.Messages.Count - 20
: 0)
.Take(20)
.Select(message => new MessageVM
{
Id = message.Id,
DateTime = message.DateTime,
Text = message.Text
}).ToList()
}).ToList();
my models are as follows:
public class Chat
{
...
public virtual ICollection<Message> Messages { get; set; }
}
public class Message
{
...
public int ChatId { get; set; }
public virtual Chat Chat { get; set; }
}
public class Entities : IdentityDbContext<ApplicationUser>
{
....
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
...
modelBuilder.Entity<Message>()
.HasRequired(p => p.Chat).WithMany(p => p.Messages).WillCascadeOnDelete(true);
}
}
thanks
I don't think you're allowed to use .Count from within the query (hence the error that you're seeing). In any case, I think you're looking at this from the wrong perspective. You should probably be using the OrderByDescending method, and then just grab the first 20 posts from there.
Something like this:
List<ChatVM> unSeenChats = db.Chats.Where(chat => !chat.Seen)
.Select(chat => new ChatVM
{
Id = chat.Id,
IsAnnonymous = chat.IsAnnonymous,
UserName = chat.UserName,
Messages = chat.Messages
.OrderByDescending(x => x.DateTime)
.Take(20)
.Select(message => new MessageVM
{
Id = message.Id,
DateTime = message.DateTime,
Text = message.Text
}).ToList()
}).ToList();
Related
The code I have below works. It's pulls in a list of every item in my One Repository.
When I add my second table to pull all the items out of THAT table I get the following error, on my DataTwo I can't figure out why it's throwing this error as the first one is programmed the exact same way.
"A specified Include path is not valid. The EntityType does not declare a navigation property with the name"
View Model
public IList<OneVM> Ones { get; set; }
public IList<TwoVM> Twos { get; set; }
public ViewModelVM()
{
this.Ones = new List<OneVM>();
this.Twos = new List<TwoVM>();
}
Working Original Code Below (Controller)
public ActionResult Directory()
{
var vm = new ViewModelVM();
var datas = _OneRepository.GetData();
vm.Datas = _mapper.Map<IList<DataVM>>(datas.OrderBy(i => i.Name));
return View(vm);
}
Desired Broken Code Below (Controller)
public ActionResult Directory()
{
var vm = new FormDirectoryVM();
var datas = _OneRepository.GetData();
var datasTwo= _TwoRepository.GetMoreData();
vm.Datas = _mapper.Map<IList<DataVM>>(datas.OrderBy(i => i.Name));
return View(vm);
vm.DatasTwo= _mapper.Map<IList<DataTwoVM>>(datasTwo);
return View(vm);
}
The problem was my Repository. I was including something that didn't need to be.
public IEnumerable<Two> GetMoreData()
{
return _context.Twos
.Include(i => i.Title) // I don't need this line
.Include(i => i.Description) // I don't need this line either
.Include(i => i.Keywords)
.Include(j => j.Text) // Or this Line
.Where(i => !i.IsDeleted)
;
}
I have a problem with the creation of LINQ query with lambda expression. I need join two tables and make some conditions. I have two tables MSR and BOMDetail.
MSR had theese columns -> MSRID, PN, Buyer,Plant EditDate.
BomDetail had theese columns -> BOMID, PN, AltQty, Plant, EditDate.
And i need to write this query into LINQ.
SELECT MSR.PN, Buyer, MSR.EditDate, MSR.Plant FROM MSR
JOIN BomDetail bd ON MSR.PN = bd.PN AND MSR.Plant = bd.Plant
WHERE LEN(ISNULL(bd.AltQty,''))>0
I need to make 2 conditions PN must equals between tables and Plant's too.
I have for result ViewModel in asp.net MVC.
public class MSRViewModel
{
public string PN { get; set; }
public string Buyer { get; set; }
public string Plant { get; set; }
public DateTime EditDate { get; set; }
}
And here is my sample, it works fine, but i don't know where i must write the second condition for bd.Plant = MSR.Plant.
var data = DbContext.BomDetails.Where(x => !string.IsNullOrEmpty(x.AltQty))
.Join(DbContext.MSRs
, bd => bd.PN,
msr => msr.PN,
(bd, msr) => new MSRViewModel
{
PN = msr.PN,
Buyer = msr.Buyer,
Plant = msr.Plant,
EditDate = msr.EditDate
}).ToList().AsEnumerable();
Thanks.
You can do this as follows:
var data = DbContext.BomDetails.Where(x => !string.IsNullOrEmpty(x.AltQty))
.Join(DbContext.MSRs
, bd => new { bd.PN, bd.Plant },
msr => new { msr.PN, msr.Plant },
(bd, msr) => new MSRViewModel
{
PN = msr.PN,
Buyer = msr.Buyer,
Plant = msr.Plant,
EditDate = msr.EditDate
}).ToList().AsEnumerable();
public IEnumerable<Temp_Order> Get_Temp(string id)
{
//List<Temp_Order> data = new List<Temp_Order>();
IEnumerable<Temp_Order> data = db.Temp_Order
.Join(db.Items,
t_id => t_id.ItemId,
I_id => I_id.ItemId,
(t_id, I_id) => new { t_id.Quantity, I_id.ItemName })
.Where(x => x.ItemName == id);
return data;
}
In this method I want IEnumerable<Temp_Order>. So I will use this in controller and return to the view.
I'm getting this error:
Cannot implicitly convert type 'System.Linq.IQueryable' to 'System.Collections.Generic.IEnumerable'. An explicit conversion exists (are you missing a cast?) E:\WORK\Projects\RMS_Live\RMS_Live\Models\Order.cs
The Join is converting your query to an IEnumerable of an anonymous type. Add a Select on the end to cast is back to Temp_Order:
public IEnumerable<Temp_Order> Get_Temp(string id)
{
//List<Temp_Order> data = new List<Temp_Order>();
IEnumerable<Temp_Order> data = db.Temp_Order
.Join(db.Items, t_id => t_id.ItemId, I_id => I_id.ItemId, (t_id, I_id) => new { t_id.Quantity, I_id.ItemName })
.Where(x => x.ItemName == id)
.Select(a => new Temp_Order
{
ItemName = a.ItemName,
Property2 = a.Property2,
//snip
});
return data;
}
EDIT:
You indicate in the comments that you want all properties from both Temp_Order and Item which means you need another class. You can get away without creating another class, but it's much simpler in the long run. So first make your class, 2 ways spring to mind, you either replicate all the properties you need or just return the 2 objects, I'll use the latter:
public class OrderItem
{
public Temp_Order Temp_Order { get; set; }
public Item Item { get; set; }
}
Now your function becomes this:
public IEnumerable<OrderItem> Get_Temp(string id)
{
IEnumerable<OrderItem> data = db.Temp_Order
.Join(db.Items,
t_id => t_id.ItemId,
I_id => I_id.ItemId,
(t_id, I_id) => new OrderItem
{
Temp_Order = t_id,
Item = I_id
})
.Where(x => x.ItemName == id);
return data;
}
And in your view, make sure you set the model type to IEnumerable<OrderItem> and you can access all the properties like this:
#Model.Temp_Order.ItemName
Iam working on nopcommerce2.8 version. I have a problem with telerik plugin implementation to create new grid.
Iam implementing a concept where for a product i want to give different price for different customer. So to assign new price for different customers, in admin panel i am creating a grid in edit productvariant page using telerik. I have created a new tab to display these details. Iam able to display customer name and price in grid, but i am not able to call update function, when i click on update button after editing a row. The same update function i called for Deleting the grid row also, so when i click on delete the same update function getting trigger. I think some setting has been missed in View. Please help me to solve this update issue.
The model, view and controller of my nopcommerce in given below.
Thanks.
//Model
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
using FluentValidation.Attributes;
using Nop.Admin.Models.Customers;
using Nop.Admin.Validators.Catalog;
using Nop.Web.Framework;
using Nop.Web.Framework.Localization;
using Nop.Web.Framework.Mvc;
using Telerik.Web.Mvc;
namespace Nop.Admin.Models.Catalog
{
public partial class CustomerProductPriceModel : BaseNopModel
{
public int Customer_Id { get; set; }
[NopResourceDisplayName("Customer Name")]
public string Customer_name { get; set; }
[NopResourceDisplayName("Price")]
public decimal Price { get; set; }
[NopResourceDisplayName("Unit")]
public string Units { get; set; }
}
}
// view
#(Html.Telerik().Grid<CustomerProductPriceModel>()
.Name("Grid")
.DataKeys(x =>
{
x.Add(y => y.Customer_Id);
})
.DataBinding(dataBinding =>
{
dataBinding.Ajax()
.Select("CustomerProductPriceList", "ProductVariant", new { productVariantId = Model.Id })
.Update("CustomerPriceUpdate", "ProductVariant", new { productVariantId = Model.Id })
.Delete("CustomerPriceUpdate", "ProductVariant", new { productVariantId = Model.Id });
})
.Columns(columns =>
{
columns.Bound(y => y.Customer_name).Width(200).ReadOnly();
columns.Bound(y => y.Price).Width(100);
columns.Command(commands =>
{
commands.Edit().Text(T("Admin.Common.Edit").Text);
commands.Delete().Text(T("Admin.Common.Delete").Text);
}).Width(180);
})
.Editable(x =>
{
x.Mode(GridEditMode.InLine);
})
.EnableCustomBinding(true)
)
// controller
[GridAction(EnableCustomBinding = true)]
public ActionResult CustomerPriceUpdate(GridCommand command, CustomerProductPriceModel model, int productVariantId)
{
if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog))
return AccessDeniedView();
return CustomerProductPriceList(command, productVariantId);
}
[HttpPost, GridAction(EnableCustomBinding = true)]
public ActionResult CustomerProductPriceList(GridCommand command, int productVariantId)
{
if (!_permissionService.Authorize(StandardPermissionProvider.ManageCatalog))
return AccessDeniedView();
var productVariant = _productService.GetProductVariantById(productVariantId);
if (productVariant == null)
throw new ArgumentException("No product variant found with the specified id");
var CustomerPrices = PrepareCustomerProductPriceModel(productVariant.Product.Id);
var CustomerPricesa = CustomerPrices
.Select(x =>
{
return new CustomerProductPriceModel()
{
Customer_Id = x.Customer_Id,
Price = x.Price,
Units = x.Units,
Customer_name = x.Customer_name
};
})
.ToList();
var model = new GridModel<CustomerProductPriceModel>
{
Data = CustomerPricesa,
Total = CustomerPrices.Count
};
return new JsonResult
{
Data = model
};
}
Is there a reason not to use the built-in customer price levels already in place in nopCommerce, or are you wanting to display all prices at once?
I'm working with MVC ASP.NET 3.5 SP1 on VS2008.
I'm looking for a way to abstract this three methods I have in my Users repository.
public User GetUser(Log log)
{
return db.Users.FirstOrDefault(u => u.Logs.Any(l => l.id.Equals(log.id)));
}
public User GetUser(Product product)
{
return db.Users.FirstOrDefault(u => u.Products.Any(pr => pr.id.Equals(product.id)));
}
public User GetUser(Photo photo)
{
return db.Users.FirstOrDefault(u => u.Photos.Any(ph => ph.id.Equals(photo.id)));
}
My DB.edmx contains the models
User [id, username, ...]
Product [id, name, ...]
Photo [id, name, ...]
Log [id, data, ...]
Is it possible to have only ONE method for all of these (and future) methods based upon model.id search?
public User GetUser(Expression<Func<User, bool>> restriction)
{
return db.Users.Where(restriction).FirstOrDefault();
}
Now use it:
var u = Repository.GetUser(u => u.Logs.Any(l => l.id.Equals(log.id)));
You can also use MS DynamicQuery:
using System.Linq.Dynamic;
//...
public User GetUser(string propertyName, int id)
{
var restriction = propertyName + ".Any(id = #0)";
return db.Users.Where(restriction, id).FirstOrDefault();
}
var u = Repository.GetUser("Logs", log.id);
I may not have the syntax quite correct, but you get the idea.
If all the associated entities (Log, Product and Photo) will be searched by a common property (id INT) then maybe you could try something like this...
First, create an interface:
public interface IUserAssociation
{
int id { get; }
}
Then each of the three classes would implement this interface like so:
public partial class Product : IUserAssociation
{
}
The the GetUser method would look like so:
public User GetUser<T>(T entity) where T : IUserAssociation
{
var type = typeof(T);
if (type == typeof(Log))
{
return db.Users.FirstOrDefault(u => u.Logs.Any(l => l.id.Equals(entity.id)));
}
else if (type == typeof(Product))
{
return db.Users.FirstOrDefault(u => u.Products.Any(pr => pr.id.Equals(entity.id)));
}
else if (type == typeof(Photo))
{
return db.Users.FirstOrDefault(u => u.Photos.Any(ph => ph.id.Equals(entity.id)));
}
else
{
throw new ArgumentException();
}
}
Then you should be able to call GetUser and pass it a Log, Photo or Product entity from one method. It is not very elegant but would work for this specific situation.
I like Craig's solution better but I'd suggest this:
Repository.GetUser(u => u.Logs, log);
Which will be possible if all your entities derive from
public interface IEntity { public int Id { get; } }
Then method will be like
public User GetUser<T, Y>(Func<T, IList<Y>> getlist, Y sample)
where T: IEntity
where Y: IEntity
{
return db.Users.Select(x => getlist(x).Any(y => y.Id == sample.Id)).FirstOrDefault();
}
Also if we take idea of S#arp Architecture that if entity1.Id == entity2.Id (for persistent entities) then Equals(entity1, entity2) - we can use getlist(x).Contains(sample).