I am using dynamic LINQ query in EF4.
Below code throws error: 'New' cannot be resolved into a valid type or function.
var x = ent.OM_COMPANY
.Where(qry)
.OrderBy("it.CM_CODE")
.Select("New(it.CM_CODE, it.CM_NAME)");
What am I doing wrong?
The below code executes without any error.
var x = from cmp in ent.OM_COMPANY
where (qry)
orderby cmp.CM_CODE
select new { cmp.CM_CODE, cmp.CM_NAME };
I don't even know how you got that first code block to compile. Both OrderBy and Select take lambdas not strings. It should be written as:
var x = ent.OM_COMPANY
.Where(qry)
.OrderBy(c => c.CM_CODE)
.Select(c => c.CM_CODE, c.CM_NAME);
Related
I'm trying to manipulate properties in a GroupBy clause to be used in a dictionary:
var lifeStages = await _dbContext.Customers
.GroupBy(x => GetLifeStage(x.DoB))
.Select(x => new { LifeStage = x.Key, Count = x.Count() })
.ToDictionaryAsync(x => x.LifeStage, x => x.Count);
I'm expecting results like
adolescent: 10,
adult: 15,
senior: 12 etc
But getting error:
Either rewrite the query in a form that can be translated,
or switch to client evaluation explicitly
by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync().
Offcourse I can't combine ToDictionary() with any of the mentioned calls, and splitting up the query did not resolve the issues or taught my anything)
I've tried with making GetLifeStage() static and async, no difference there as well. The method gets called, performs what it needs to do, and still GroupBy can't be translated
If I leave out the Select() part and work with the Key of the GroupBy, same error:
"...could not be translated."
I saw an error too that said I couldn't combine a GroupBy() with a ToDictionary() during try-outs, but doesn't seem to pop up atm.
As I'm running out of ideas, all suggestions are welcome!
update:
private LifeStage GetLifeStage(DateTimeOffset doB)
{
var ageInMonths = Math.Abs(12 * (doB.Year - DateTimeOffset.UtcNow.Year) + doB.Month - DateTimeOffset.UtcNow.Month);
switch (ageInMonths)
{
case < 216:
return LifeStage.Adolescent;
case < 780:
return LifeStage.Adult;
case >= 780:
return LifeStage.Senior;
}
}
The problem is the usage of the custom GetLifeStage method inside the GroupBy expression. Custom methods cannot be translated to SQL because the query translator code has no way to know what is inside that method. And it cannot be called because there are no objects at all during the translation process.
In order to make it translatable, you have to replace the custom method call with its body, converted to translatable expression - basically something which can be used as expression bodied method. You can't use variables and switch, but you can use conditional operators. Instead of variable, you could use intermediate projection (Select).
Here is the equivalent translatable query:
var lifeStages = await _dbContext.Customers
.Select(c => new { Customer = c, AgeInMonths = Math.Abs(12 * (c.DoB.Year - DateTimeOffset.UtcNow.Year) + c.DoB.Month - DateTimeOffset.UtcNow.Month) })
.GroupBy(x => x.AgeInMonths < 216 ? LifeStage.Adolescent : x.AgeInMonths < 780 ? LifeStage.Adult : LifeStage.Senior)
// the rest is the same as original
.Select(x => new { LifeStage = x.Key, Count = x.Count() })
.ToDictionaryAsync(x => x.LifeStage, x => x.Count);
I am trying to implement a query in EF Core in which I need to get data where any name in a string array is contained by the name of the data object. Here is the code sample:
var searchKeys = search.Split(' ');
var objects = _db.Objects
.Where(o => searchKeys.Any(k => o.name.Contains(k))))
.OrderBy(o => o.Name)
.Select o
But the query cannot be translated resulting in the following error:
The LINQ expression 'DbSet
.Where(o => __searchKeys_1
.Any(k => __Functions_2
.Contains(
_: o.Name,
propertyReference: k)))' could not be translated. Either rewrite the query in a form that can be translated, or switch
to client evaluation explicitly by inserting a call to either
AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See
https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
How can I contruct the query to fix the error?
For some reason, I could not get Obie's answer to work for me in .Net Core 3.1. Luckily, the LinqKit NuGet package has been upgraded for .Net Core. So I defined this extension method:
// Where any search predicates are true.
public static IQueryable<T> WhereAny<T>(this IQueryable<T> q, params Expression<Func<T, bool>>[] predicates)
{
var orPredicate = PredicateBuilder.New<T>();
foreach (var predicate in predicates)
{
orPredicate = orPredicate.Or(predicate);
}
return q.AsExpandable().Where(orPredicate);
}
And then you would use it like this:
var searchKeys = search.Split(' ');
var predicates = searchKeys.Select(k => (Expression<Func<MyObject, bool>>)(x => x.Name.Contains(k)));
var objects = _db.Objects
.WhereAny(predicates.ToArray())
.OrderBy(o => o.Name);
This works for me:
var searchKeys = search.Split(' ');
var objects = _db.Objects
.Where(o => searchKeys.Any(k => o.Name.Contains(k)))
.OrderBy(o => o.Name)
.Select(o => o);
I am not sure why I am getting the error: "Must be reducible node"
This is my query. I am running Core 2 with EF Core 2.2 (So I should have the fixes that occurred in previous versions)
IQueryable<Gizmo> gizmos = _context.Gizmo;
IQueryable<GizmoViewModel> dataReferences = (
gizmos.SelectMany(j => j.DataReferences.Select(r =>
new GizmoViewModel()
{
GizmoId = j.Id,
DataId = r.DataId
}
))
);
Simply (and sadly) you are hitting one of the current EF Core query translation bugs.
Looks like it's caused by the accessing the outer SelectMany lambda parameter inside the inner Select expression.
The workaround is to use another SelectMany overload having a second lambda with both outer and inner parameters (which I guess is used by C# compiler when converting LINQ query syntax):
IQueryable<GizmoViewModel> dataReferences = (
gizmos.SelectMany(j => j.DataReferences, (j, r) =>
new GizmoViewModel()
{
GizmoId = j.Id,
DataId = r.DataId
}
)
);
Try to include DataReferences maybe?
Your code revised:
IQueryable<GizmoViewModel> dataReferences = (
gizmos.SelectMany(j => j.DataReferences.Select(r =>
new GizmoViewModel()
{
GizmoId = j.Id,
DataId = r.DataId
}
))
.Include(m => m.DataReferences)
I am somewhat new to expression trees and I just don't quite understand some things.
What I need to do is send in a list of values and select the columns for an entity from those values. So I would make a call something like this:
DATASTORE<Contact> dst = new DATASTORE<Contact>();//DATASTORE is implemented below.
List<string> lColumns = new List<string>() { "ID", "NAME" };//List of columns
dst.SelectColumns(lColumns);//Selection Command
I want that to be translated into code like this (Contact is an entity using the EF4):
Contact.Select(i => new Contact { ID = i.ID, NAME = i.NAME });
So let's say I have the following code:
public Class<t> DATASTORE where t : EntityObject
{
public Expression<Func<t, t>> SelectColumns(List<string> columns)
{
ParameterExpression i = Expression.Parameter(typeof(t), "i");
List<MemberBinding> bindings = new List<MemberBinding>();
foreach (PropertyInfo propinfo in typeof(t).GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
if (columns.Contains(propinfo.Name))
{
MemberBinding binding = Expression.Bind(propinfo, Expression.Property(i, propinfo.Name));
bindings.Add(binding);
}
}
Expression expMemberInit = Expression.MemberInit(Expression.New(typeof(t)), bindings);
return Expression.Lambda<Func<t, t>>(expMemberInit, i);
}
When I ran the above code I got the following error:
The entity or complex type 'Contact' cannot be constructed in a LINQ to Entities query.
I looked at the body of the query and it emitted the following code:
{i => new Contact() {ID = i.ID, NAME = i.NAME}}
I am pretty sure that I should be able to construct the a new entity because I wrote this line explicitly as a test to see if this could be done:
.Select(i => new Contact{ ID = i.ID, NAME = i.NAME })
This worked, but I need to construct the select dynamically.
I tried decompiling a straight query(first time I have looked at the low level code) and I can't quite translate it. The high level code that I entered is:
Expression<Func<Contact, Contact>> expression = z =>
new Contact { ID = z.ID, NAME = z.NAME };
Changing the framework used in the decompiler I get this code:
ParameterExpression expression2;
Expression<Func<Contact, Contact>> expression =
Expression.Lambda<Func<Contact, Contact>>
(Expression.MemberInit(Expression.New((ConstructorInfo) methodof(Contact..ctor),
new Expression[0]), new MemberBinding[] { Expression.Bind((MethodInfo)
methodof(Contact.set_ID), Expression.Property(expression2 = Expression.Parameter(typeof(Contact), "z"), (MethodInfo)
methodof(Contact.get_ID))), Expression.Bind((MethodInfo)
methodof(Contact.set_NAME), Expression.Property(expression2, (MethodInfo)
methodof(Contact.get_NAME))) }), new ParameterExpression[] { expression2
});
I have looked several places to try and understand this but I haven't quite gotten it yet. Can anyone help?
These are some places that I have looked:
msdn blog -- This is exactly what I want to do but my decopiled code soes not have Expression.Call.
msdn MemberInit
msdn Expression Property
stackoverflow EF only get specific columns -- This is close but this seems like it is doing the same thing as if i just use a select off of a query.
stackoverflow lambda expressions to be used in select query -- The answer here is exactly what I want to do, I just don't understand how to translate the decompiled code to
C#.
When I did it last time I projected result to not mapped class (not entity) and it worked, everything else was the same as in your code. Are you sure that not dynamic query like .Select(i => new Contact{ ID = i.ID, NAME = i.NAME }) works?
I'm having problem using queries like this with Entity Framework 4 Code First:
var entities = context.TestEntities.Where( e => context.TestEntities2.Count() > 0)
The above query will generate the following exception:
Unable to create a constant value of
type 'TestModel.TestEntities2'. Only
primitive types ('such as Int32,
String, and Guid') are supported in
this context.
The same code works if I use the model designer and generate the POCO-classes and thus using a ObjectContext instead.
EDIT: It works in a console-application but not while using my repository in an MVC 3 project.
EDIT 2: How about this:
var userProfile = ctx.UserProfiles.Where(p => p.User.Id == user.Id).SingleOrDefault();
return ctx.Feeds.Where( f => ctx.ProfileFollowers.Count() > 0 ).ToList();
The above two lines throws the exception. Commenting out the first line solves the problem. Bug in DbContext?
//var userProfile = ctx.UserProfiles.Where(p => p.User.Id == user.Id).SingleOrDefault();
return ctx.Feeds.Where( f => ctx.ProfileFollowers.Count() > 0 ).ToList();
Posted to http://social.msdn.microsoft.com/Forums/en-US/adonetefx/thread/2fb5ceea-9f30-4665-af98-945c6485f60b
Try the Any method:
var q = context.TestEntities.Where(a=>context.TestEntities2.Any());
This code results in the EXISTS clause:
SELECT
[Extent1].[ProductID] AS [ProductID],
...
FROM [dbo].[Products] AS [Extent1]
WHERE EXISTS (SELECT
1 AS [C1]
FROM [dbo].[Regions] AS [Extent2]
UPD: In case of repositories the correct way is to execute the first query and then the second one:
if(context.TestEntities2.Count() > 0)
var q = context.TestEntities.Select(t=>t);