LINQ to Entities Contains Query - entity-framework

I'm trying to use Contains() in a simple query but it is failing, with the error :
Unable to create a constant value of type 'NewsletterApp.Models.NewsletterUser'. Only primitive types ('such as Int32, String, and Guid') are supported in this context.
Edit The intellisense actually directs me to use the NewsletterUser in Contains() -'(NewsletterUser item)'
I read that there were issues searching for an object using Contains() using EF with .NET 3.5, but I am using EF4.2 (also tried 4.1) with .NET 4.0 .
Code is below:
var db = new MyContext();
var newsletterUser = db.NewsletterUsers.Find(UserID);
var subscriberList = db.Subscribers
.Where(x => x.NewsletterList.ListOwner.NewsletterUsers.Contains(newsletterUser))
.ToList();

I suspect you want this
var db = new MyContext();
var newsletterUser = db.NewsletterUsers.Find(UserID);
var subscriberList = db.Subscribers
.Where(x => x.NewsletterList.ListOwner.NewsletterUsers
.Any(y => y.UserId == newsletterUser.UserId))
.ToList();
Any() checks for the existence of a item that fulfils the criteria specified in the lambda: "y => y.UserId == newsletterUser.UserId".
The exception you were getting: "Only primitive types ('such as Int32, String, and Guid') are supported in this context" is due to limitations set by LINQ to Entities. LINQ to Entities needs to resolve your query in a way that it can express to the database, and it can't do that with the Contains() method with anything other than a primitive type.
The thing is, the code you posted does run fine if you run it against an in memory collection (LINQ to Objects) - that's why it isn't flagged by the compiler.

Your query is wrong. Instead of comparing a property or field, you are comparing the whole object or entity, which can't be done in this manner.
Try the following code and it will work
var db = new MyContext();
var newsletterUser = db.NewsletterUsers.Find(UserID);
var subscriberList = db.Subscribers
.Where(x => x.NewsletterList.ListOwner.NewsletterUsers.UserId.Contains(newsletterUser.UserID))
.ToList();

Related

EF Core 3 GroupBy multiple columns Count Throws with extensions but linq works

Here is the one that throws full exception:
var duplicateCountOriginal = _db.TableName
.GroupBy(g => new {g.ColumnA, g.ColumnB, g.ColumnC})
.Count(g => g.Count() > 1);
Exception:
System.ArgumentException: Expression of type 'System.Func2[System.Linq.IGrouping2[Microsoft.EntityFrameworkCore.Storage.ValueBuffer,Microsoft.EntityFrameworkCore.Storage.ValueBuffer],Microsoft.EntityFrameworkCore.Storage.ValueBuffer]' cannot be used for parameter of type 'System.Func2[Microsoft.EntityFrameworkCore.Storage.ValueBuffer,Microsoft.EntityFrameworkCore.Storage.ValueBuffer]' of method 'System.Collections.Generic.IEnumerable1[Microsoft.EntityFrameworkCore.Storage.ValueBuffer] Select[ValueBuffer,ValueBuffer](System.Collections.Generic.IEnumerable1[Microsoft.EntityFrameworkCore.Storage.ValueBuffer], System.Func2[Microsoft.EntityFrameworkCore.Storage.ValueBuffer,Microsoft.EntityFrameworkCore.Storage.ValueBuffer])' (Parameter 'arg1')
But the same thing works when it is written as linq (I prefer extensions)
var duplicateCount =
from a in _db.TableName
group a by new {a.ColumnA, a.ColumnB, a.ColumnC}
into g
where g.Count() > 1
select g.Key;
duplicateCount.Count()
I am unable to understand why one works or the other doesn't.
Also if I change the first one a little bit based on EF Core 3 changes like the following
var duplicateCountOriginal = _db.TableName
.GroupBy(g => new {g.ColumnA, g.ColumnB, g.ColumnC})
.AsEnumerable()
.Count(g => g.Count() > 1);
I get the following exception:
System.InvalidOperationException: Client projection contains reference to constant expression of 'Microsoft.EntityFrameworkCore.Metadata.IPropertyBase' which is being passed as argument to method 'TryReadValue'. This could potentially cause memory leak. Consider assigning this constant to local variable and using the variable in the query instead. See https://go.microsoft.com/fwlink/?linkid=2103067 for more information.
According to me, the link given by ms has no meaning to the whatever problem here is.
Please LMK if there is any logical explanation.
There is no logical explanation. Just EF Core query translation is still far from perfect and have many defects/bugs/unhandled cases.
In this particular the problem is not the query syntax or method syntax (what you call extensions), but the lack of Select after GroupBy. If you rewrite the method syntax query similar to the one using query syntax, i.e. add .Where, .Select and then Count:
var duplicateCount = _db.TableName
.GroupBy(g => new {g.ColumnA, g.ColumnB, g.ColumnC})
.Where(g => g.Count() > 1)
.Select(g => g.Key)
.Count();
then it will be translated and executed successfully.

How to perform subtraction between DateTime in a Linq to Sql Select() method

I've a linq query :
var NextWeekDate = DateTime.Now.AddDays(7);
var BirthData = db.EmployeeMasterAs
.Where(x => x.Emp_BirthDate >= CurrentDate)
.Select(x => new { x.Emp_BirthDate,
DaysRemaining = (NextWeekDate - x.Emp_BirthDate).Value.TotalDays
})
.OrderBy(x => x.Emp_BirthDate)
.ToList();
Note the element in Select() method, DaysRemaining = (NextWeekDate - x.Emp_BirthDate).Value.TotalDays, I want to get the difference between dates in days and save that to DaysRemaining, this query is not working and the exception that it throws :
DbArithmeticExpression arguments must have a numeric common type.
I don't know exactly how to achieve this, Any Ideas?
I think that LinqToSql does not support DateTime.Subtract. But you can use the preexisting function SqlMethods.DateDiffDay (https://msdn.microsoft.com/en-us/library/bb468730(v=vs.110).aspx)
Edit: SqlMethods is only intended for SQL Server. DbFunctions is the helper class to pick regardless of the database type.
Yep, Got it, So here is how it goes :
Performing arithmetic operations with Dates and Times is not supported in EF. EntityFramework cannot convert your code to SQL. Instead of that you can use DbFunctions.DiffDays( startExpression, endExpression) method:
db.EmployeeMasterAs
.Where(x => x.Emp_BirthDate >= CurrentDate)
.Select(x => new { x.Emp_BirthDate,
DaysRemaining = DbFunctions.DiffDays(x.Emp_BirthDate,NextWeek)
})
.OrderBy(x => x.Emp_BirthDate)
.ToList();
Furthermore : DbFunctions Functions methods are called canonical functions. And these are a set of functions, which are supported by all Entity Framework providers. These canonical functions will be translated to the corresponding data source functionality for the provider. Canonical functions are the preferred way to access functionality outside the core language, because they keep the queries portable.

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

I'm using MVC and Entity Framework. I've created a class in my model folder with this code below. I keep getting the error message above with both queries below. I know there is a known issue on referencing non-scalar variables, but I'm not sure how to implement a workaround:
http://msdn.microsoft.com/en-us/library/bb896317.aspx#Y1442
private MovieLibraryDBEntities movieLibraryDBEntitiesContext;
public int getNumberOfEntriesReserved()
{
return (from m in movieLibraryDBEntitiesContext.Movies
where m.CheckedOut.Equals(1)
select m).Count();
//return movieLibraryDBEntitiesContext.Movies
// .Where(e => e.CheckedOut.Equals(1))
// .Select (e => e.Title).Count();
}
You cannot use m.CheckedOut.Equals(1) in linq-to-entities query. Use m.CheckedOut == 1 but CheckedOut must be integer.
This is an older question. I had the same problem when trying to filter a nullable column using the IQueryable interface. I solved the problem by first checking to see if the object had a value and then checking the value.
widgets = widgets.Where(x => x.ID.HasValue.Equals(true) && x.ID.Value.Equals(widgetID));
same issue using Any()
i had to change my where clause to search on primitive types, for me int
so this
where order.User == user
becomes this
where order.User.UserId == user.UserId
There is a blog post explaining the quirk.

EF1: Filtering derived types of entity class using .OfType<> by passing a string value

I have a situation where I'm trying to filter a LINQ select using a derived sub class.
ctx.BaseEntity.OfType<SubClass>() - this works fine.
However I'd like to do this using a string value instead. I've come across a performance barrier when I have lots (>20) Sub Classes and selecting an Entity without using OfType just isn't an option. I have a generic UI that renders from the base class, so I don't know what Class Type will be returned at compile time.
So what I'd like to do is this:
Perform a projected Select where I
return just the SubClassType from
the database
Perform a second select
using this value as the OfType to
only select the relevant related
entity from the database (No mass
unions generated)
int id = 1;
var classType = (from c in ctx.BaseClass.Include("ClassType")
where c.id == id
select new
{
c.ClassType.TypeName
}).First();
BaseClass caseQuery = ctx.BaseClass.OfType<classType.TypeName>()
.Include("ClassType")
.Include("ChildEntity1")
.Include("ChildEntity2")
.Where(x => x.id== id);
But obviously this won't work because OfType requires a Type and not a string.
Any ideas on how I can achieve this?
Update:
As a side note to the original question, it turns out that the moment you project a query that uses a Navigation Property - it builds the monster SQL too, so I've ended up using a stored procedure to populate my ClassType entity from the BaseClass Id.
So I've just got it to work using eSQL, which I'd never used before. I've posted the code here just in case it helps someone. Has anyone else got a more strongly typed solution they can think of?
BaseClass caseQuery = ctx.BaseClass.CreateQuery<BaseClass>("SELECT VALUE c FROM OFTYPE(Entities.[BaseClass],namespace.[" + classType.TypeName + "]) as c")
.Include("ClassType")
.Include("ChildEntity1")
.Include("ChildEntity2")
.Where(x => x.id== id).FirstOrDefault();
To answer the headline question about calling OfType with a string / runtime type, you can do the following:
// Get the type, assuming the derived type is defined in the same assembly
// as the base class and you have the type name as a string
var typeToFilter = typeof(BaseClass)
.Assembly
.GetType("Namespace." + derivedTypeName);
// The use reflection to get the OfType method and call it directly
MethodInfo ofType = typeof(Queryable).GetMethod("OfType");
MethodInfo ofTypeGeneric = method.MakeGenericMethod(new Type[] { typeToFilter });
var result = (IQueryable<Equipment>)generic.Invoke(null, new object[] { equipment });
Combine this with your stored procedure to get the class name and you (should?) avoid the massive join - I don't have table-per-type implementation to play with so I can't test.

Generated SQL with PredicateBuilder, LINQPad and operator ANY

I previously asked a question about chaining conditions in Linq To Entities.
Now I use LinqKit and everything works fine.
I want to see the generated SQL and after reading this answer, I use LinqPad.
This is my statement:
var predProduct = PredicateBuilder.True<Product>();
var predColorLanguage = PredicateBuilder.True<ColorLanguage>();
predProduct = predProduct.And(p => p.IsComplete);
predColorLanguage = predColorLanguage.And(c => c.IdColorEntity.Products.AsQueryable().Any(expr));
ColorLanguages.Where(predColorLanguage).Dump();
The code works in VS2008, compile and produce the correct result set, but in LinqPad, I've the following error:
NotSupportedException: The overload query operator 'Any' used is not Supported.
How can I see the generated SQL if LINQPad fails?
EDIT
If I write
var predColorLanguage = PredicateBuilder.True<ColorLanguage>();
predColorLanguage = predColorLanguage.And(c => c.IdColorEntity.Products.Any((p => p.IsComplete));
ColorLanguages.Where(predColorLanguage).Dump();
works... WTF?
As you're using LINQKit, you can make this work by calling Compile() on the expression that feeds the EntitySet, and then calling AsExpandable() on the main query:
var predProduct = PredicateBuilder.True<Product>();
var predColorLanguage = PredicateBuilder.True<ColorLanguage>();
predProduct = predProduct.And(p => p.IsComplete);
predColorLanguage = predColorLanguage.And (
c => c.IdColorEntity.Products.Any(predProduct.Compile()));
ColorLanguages.AsExpandable().Where(predColorLanguage).Dump();
As explained in the LINQKit article, the Compile method never actually runs: AsExpandable strips it out and modifies the expression tree so that it works with LINQ to SQL.