The specified type member 'UsersCount' is not supported in LINQ to Entities - asp.net-mvc

I have such POCO entity
public class Product : Entity
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
[Required]
[MaxLength(50)]
public string Name { get; set; }
public virtual ICollection<Order> Orders { get; set; }
[NotMapped]
public int UsersCount
{
get
{
return Orders.Count();
}
}
}
Product access method
public IQueryable<Product> GetAll()
{
return _context.Product.Include(I=>I.Orders);
}
When I load all products into View
var model = _productService.GetAll().Select(p => new AdminProductViewModel
{
Active = p.Active,
Id = p.Id,
Name = p.Name,
UsersCount = p.UsersCount
}).ToList();
I get exception
The specified type member 'UsersCount' is not supported in LINQ to
Entities.
I really can't understand why Linq to Entity gives exception. Maybe someone explain what is wrong?
We also use calculated fields in another application like this
public class User : Entity
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
[Required]
[MaxLength(50)]
public string Email { get; set; }
[MaxLength(50)]
public string FirstName { get; set; }
[MaxLength(50)]
public string LastName { get; set; }
public virtual ICollection<Order> Orders { get; set; }
public virtual ICollection<Statistic> Statistics { get; set; }
[NotMapped]
public bool Active
{
get
{
return Orders.Any(c => c.Active && (c.TransactionType == TransactionType.Order || c.TransactionType == TransactionType.Subscription));
}
}
[NotMapped]
public int CreditsLeft
{
get
{
return Orders.Where(w => w.Active).Sum(p => p.Credits != null ? p.Credits.Value : 0);
}
}
}
public User Get(int id)
{
return _context.User.FirstOrDefault(u => u.Id == id);
}
var user = _userService.Get(_authUser.Id);
var model = new UserViewModel
{
Active = user.Active,
FullName = user.FullName,
Email = user.Email,
};
and have no problems, EF6 don't give any exception though it also has two calculated fields User.Active and User.CreditsLeft

Keep in mind that LINQ to Entities tries to translate each LINQ statement into SQL. Your statement...
var model = _productService.GetAll().Select(p => new AdminProductViewModel...
...is a LINQ extension method (Select) against an IQueryable (_productService.GetAll()). As the documentation shows, this method takes an Expression as argument.
You can see an expression as a tree of tokens that express the task it should execute. A LINQ provider, simply said, is a dictionary of tokens in "expression language" to tokens in some other language, SQL in this case. The whole statement is translated into SQL and executed by the database. The .Net runtime only sends the statement away and processes the returned result.
Inspecting EF's source code reveals that many tokens are hard-coded: all SQL keywords, a number of built-in ("canonical") functions (like DATEDIFF) and a selection of .Net methods. Other tokens are added by mapping entity properties to database columns. Recently, ToString() was added to the .Net part of the dictionary. In EF6 we can write...
_context.Product.Select(p => p.Id.ToString())
Before that, this would raise the infamous
LINQ to Entities does not recognize the method 'System.String ToString()'
Your exception has the same cause, but it pertains to members in stead of methods. p.UsersCount is not in the dictionary because it is not mapped.
We also use calculated fields in another application like this
Here a User has been fetched from the database and materialized as a C# object. Now when you access its properties it's just .Net code running. There's no SQL translation going on here. Well... it probably triggers lazy loading (of orders and credits), but the act of accessing the property does not happen in the context of an expression.
Likewise, you can access UsersCount once you've got a Product object. If you want the database to do the heavy lifting of counting the orders, you'll have to use the expression in the LINQ statement:
var model = _productService.GetAll().Select(p => new AdminProductViewModel
{
Active = p.Active,
Id = p.Id,
Name = p.Name,
UsersCount = p.Orders.Count()
}).ToList();

Try this instead:
var model = _productService.GetAll().Select(p => new AdminProductViewModel
{
Active = p.Active,
Id = p.Id,
Name = p.Name,
UsersCount = p.Orders.Count()
}).ToList();
Linq to Entities can't translate the Product.UsersCount property into sql so it gives you the error message
The specified type member 'UsersCount' is not supported in LINQ to
Entities

Related

Return last value of a column

I am trying to get the last value of a record from the database. I am using entity framework. I am trying to get the last value of the balance and deduct the amount user enters to get the new balance. I am new to this and trying to create a simple expense management system.
My controller
public ActionResult Create([Bind(Include = "ExpenseId,ExpenseFor,DateTime,Amount,Balance,RowVersion")] Expense expense)
{
if (ModelState.IsValid)
{
var a = db.Expenses.Select(b => b.Balance);
var c = a.Last();
expense.Balance = c - expense.Amount;
db.Expenses.Add(expense);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(expense);
}
return View(expense);
}
My model looks like this
public class Expense
{
public int ExpenseId { get; set; }
public string ExpenseFor { get; set; }
public DateTime DateTime { get; set; }
public Decimal? Amount { get; set; }
public Decimal? Balance { get; set; }
[Timestamp]
public byte[] RowVersion { get; set; }
}
When I try to create new records, it says that the Method cannot be translated into a store expression. I would really appreciate any help with this.
If you use SQL server, it's no wonder .Last()function is not going to work.
There is no such things as (select last) in SQL server, so Entity basicaly fails to translate it to a database SQL server language. This is what you have to do :
var v = db.Expenses.OrderByDescending(t => t.ColumnName).First();
Or something similar, depending on what you want.
Try to think of a way to turn the query around and use First() ... or FirstOrDefault() if your are afraid of potential null values.
Your own solution :
var v = db.Expenses.OrderByDescending(t => t.ExpenseId).First();

Unable to cast the type 'System.Int32' to type 'System.Object'. LINQ to Entities

I am working on MVC and Entity Framework. I have written a function for multiple record delete.
The model is:
public partial class Category
{
public Category()
{
//this.Products = new HashSet<Product>();
}
public int CategoryID { get; set; }
public string CategoryName { get; set; }
public string Description { get; set; }
public byte[] Picture { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
Controller is:
public ActionResult DeleteMultipleCategories(int[] id)
{
try
{
foreach (Category item in _db.Categories.Where(x => id.Equals(x.CategoryID)).ToList())
_db.Categories.Remove(item);
_db.SaveChanges();
return new HttpStatusCodeResult(HttpStatusCode.OK);
}
catch
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
It is giving an error like
"Unable to cast the type 'System.Int32' to type 'System.Object'. LINQ to Entities only supports casting EDM primitive or enumeration types.".
The statement "id.Equals(x.CategoryID)).ToList()" is responsible the error.
If I change it to id.Contains(x.CategoryID)).ToList(), it is working fine.
I don't want to use "Contains" as it will not give actual result e.g. if I want to delete the record no. 1 it will also delete record no. 11, 111 etc.
Any help will be thankfully accepted.
Partha
For the int datatype you have to use == as the comparator. So your linq statement should be something like .where(m =>m.id == x.CategoryID).ToList()

(MVC C#)Advice on my Maintenance Scheduling system with Maintenance Records

I have this maintenance scheduling system, and in im using MVC C# Entity Framework,
I have this table
Truck Table that has - truck id, registration no., kilometer run reading, and i have an JobOrder Table, i want to get the truck id in the truck table so that i can add a JobOrder on a specific Truck i have this JobOrder Controller
public ActionResult AddJobOrder(JobOrderModel jo, int id)
{
var AddJobOrder = db.trucks.FirstOrDefault(s => s.id == id);
var addjo = new joborder()
{
truck_no = AddJobOrder,
description = jo.Description,
worked_performed = jo.worked_performed,
quantity = jo.Quantity,
spare_parts = jo.SpareParts,
run = jo.kilometer_run,
date_finished = jo.DateFinished,
date_started = jo.DateFinished,
};
if (!ModelState.IsValid)
{
db.joborders.Add(addjo);
db.SaveChanges();
return View(jo);
}
return View(jo);
}
I receive the following error:
Error 4 Cannot implicitly convert type 'Pms_system.truck' to 'int'
This is my model
public class JobOrderModel
{
public int truck_no { get; set; }
public DateTime DateStarted { get; set; }
public DateTime DateFinished { get; set; }
public string SpareParts { get; set; }
public int Quantity { get; set; }
public string Description { get; set; }
public int kilometer_run { get; set; }
public string worked_performed { get; set; }
}
Please help me to get the truck id.
It looks like this is just a matter of getting the ID out of the truck - after all, your oddly-named AddJobOrder variable is presumably of type Truck or something similar. I suspect you just need something like:
truck_no = AddJobOrder.id,
After all, that's how you're getting at the truck ID in the query just beforehand. It's not entirely clear why you need the query at all if you only need the truck ID, which has been provided to the method anyway - all you're doing at the moment is allowing you to check whether or not there is such a record, although you should then actually do the check by seeing whether FirstOrDefault returned null.
I would also strongly advise you to take a good look at the names you're using, both in terms of capitalization and semantic names too. (Your AddJobOrder variable should be called truck or something similar by the sounds of it. The fact that it's the same name as the method is doubly confusing!)

Use Entity Framework to store user specific data

I have read a few articles about .Net Entity Framework that really didn't make me want to try it out. But now I have started a small test.
I set up a MVC 3 site that will handle economy transactions for my family, just for fun. So I setup Membership provider and get the login functions working. Usually I use the Membership Guid in a column to identify each row to a specific user.
I setup this class in my project:
namespace mEconomy.Models
{
public class Transaction
{
public Guid UserID { get; set; }
public int TransactionID { get; set; }
public DateTime Date { get; set; }
public string Text { get; set; }
public string Category { get; set; }
public decimal Amount { get; set; }
}
public class TransactionDBContext : DbContext
{
public DbSet<Transaction> Transactions { get; set; }
}
}
Works fine but I get the information on all users. If user A logs on and creates a few transaction then user B can create an account and see them. What is best practice here? How do I keep the user data separated?
I even tried setting the UserID as a private like this:
private Guid UserID = (Guid)Membership.GetUser().ProviderUserKey;
But that didn't work at all.
In your controller, use a linq query or the fluent api to retrieve only the desired entries:
TransactionDBContext db = new TransactionDBContext();
Guid userID = (Guid)Membership.GetUser().ProviderUserKey;
Query builder:
var transactions = db.Transactions.Where(t => t.UserId == userID);
Or Linq:
var transactions = from transaction in db.Transactions
where transaction.UserId == userID
select transaction;
Edit:
Do you want to always get the data filtered by userId without having to do where clauses in every place?
Your best bet in this case is to create a method in the model to retrieve this data for you:
// In your model code
public IQueryable<Transaction> FromCurrentUser()
{
Guid userID = (Guid)Membership.GetUser().ProviderUserKey;
return db.Transactions.Where(t => t.UserId == userID);
}
In your "Transactions" list page, just limit the transactions by the UserId.
public ActionResult List() {
using (var db = new TransactionDBContext()) {
var results = db.Transactions.Where(x => x.UserID == (Guid)Membership.GetUser().ProviderUserKey).ToList();
return View(results);
}
}

Unable to create a constant value of type 'T'. Only primitive types ('such as Int32, String, and Guid') are supported in this context

I see alot of question about this error, but some one can tell me why I get this error in my code?
I have the User and Group in my app, they have many to many relationship:
public class Group
{
[Key]
public int GId { get; set; }
public string GName { get; set; }
public virtual ICollection<UserProfile> Members { get; set; }
public Group()
{
Members = new HashSet<UserProfile>();
}
}
public class UserProfile
{
[Key]
public Guid UserId { get; set; }
[Required]
public string UserName { get; set; }
public virtual ICollection<Group> Groups { get; set; }
public UserProfile()
{
Groups = new HashSet<Group>();
}
}
I want to get all the Group that a User has Join ans pass it to a ViewBag, so:
UserProfile user = core.Profiles.Find(1);
//ok, no error in controller, but view...
ViewBag.JoinGroups = core.Groups.Where(g => g.Members.Contains(user));
But I get the error at View:
#if (ViewBag.JoinGroups != null)
{
foreach (var g in ViewBag.JoinGroups)//My issue start here
{
<p>#g.GId</p>
}
}
And it said:
Unable to create a constant value of type 'Project.Model.UserProfile'.
Only primitive types ('such as Int32, String, and Guid') are supported
in this context.
Do I missing any thing?
The message is clear: EF Linq queries do not support passing entities.
You can work around it by changing this piece:
UserProfile user = core.Profiles.Find(1);
ViewBag.JoinGroups = core.Groups.Where(g => g.Members.Contains(user));
For this:
ViewBag.JoinGroups = core.Groups.Where(g => g.Members.Select(x => x.UserId)
.Contains(1));
This is not specific to a ViewBag or anything. It's just the deferred execution pitfall: not until the foreach is the query executed. You would have seen the exception earlier by doing core.Groups.Where(g => g.Members.Contains(user)).ToList();.
By the way you pose it is clear that you already know that referencing non-scalar variables is not supported in entity framework, but allow me to mention it for the sake of completeness.

Resources