Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
144 views
in Technique[技术] by (71.8m points)

c# - Howto use predicates in LINQ to Entities for Entity Framework objects

I'm using LINQ to Entities for Entity Framework objects in my Data Access Layer.

My goal is to filter as much as I can from the database, without applying filtering logic to in-memory results.

For that purpose Business Logic Layer passes a predicate to Data Access Layer.

I mean

Func<MyEntity, bool>

So, if I use this predicate directly, like

public IQueryable<MyEntity> GetAllMatchedEntities(Func<MyEntity, Boolean> isMatched)
{
    return qry = _Context.MyEntities.Where(x => isMatched(x));
}

I'm getting the exception

[System.NotSupportedException] --- {"The LINQ expression node type 'Invoke' is not supported in LINQ to Entities."}

Solution in that question suggests to use AsExpandable() method from LINQKit library.

But again, using

public IQueryable<MyEntity> GetAllMatchedEntities(Func<MyEntity, Boolean> isMatched)
{
    return qry = _Context.MyEntities.AsExpandable().Where(x => isMatched(x));
}

I'm getting the exception

Unable to cast object of type 'System.Linq.Expressions.FieldExpression' to type 'System.Linq.Expressions.LambdaExpression'

Is there way to use predicate in LINQ to Entities query for Entity Framework objects, so that it is correctly transformed it into a SQL statement.

Thank you.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You don't need LinqKit to do this. Just remember to use

Expression<Func<MyEntity, bool>>

instead of

Func<MyEntity, bool>

Something like this:

public IQueryable<MyEntity> GetAllMatchedEntities(Expression<Func<MyEntity, Boolean>> predicate)
{
    return _Context.MyEntities.Where(predicate);
}

You have to use Expression because Linq to Entities needs to translate your lambda to SQL.

When you use Func your lambda is compiled to IL but when using Expression it is an expression tree that Linq to Entities can transverse and convert.

This works with expressions that Linq to Entities understands.

If it keeps failing then your expression does something that Linq to Entities can not translate to SQL. In that case I don't think LinqKit will help.

Edit:

There is no conversion needed. Just define the method GetAllMatchedEntities with an Expression parameter and use it in the same way you would with a Func parameter. The compiler does the rest.

There are three ways you can use GetAllMatchedEntities.

1) With an inline lambda expression:

this.GetAllMatchedEntities(x => x.Age > 18)

2) Define your Expression as a field (can be a variable also)

private readonly Expression<Func<MyEntity, bool>> IsMatch = x => x.Age > 18;
...then use it
this.GetAllMatchedEntities(IsMatch)

3) You can create your expression manually. The downsize is more code and you miss the compile-time checks.

public Expression<Func<MyEntity, bool>>  IsMatchedExpression()
{
    var parameterExpression = Expression.Parameter(typeof (MyEntity));
    var propertyOrField = Expression.PropertyOrField(parameterExpression, "Age");
    var binaryExpression = Expression.GreaterThan(propertyOrField, Expression.Constant(18));
    return Expression.Lambda<Func<MyEntity, bool>>(binaryExpression, parameterExpression);
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...