[英]C# Linq Lambda Expression for Entity Framework Query Passing Custom Expression to Where Condition
我有兩個名為 ShipmentType 和 Books 的表。 已為這些表映射實體類。 創建了另一個名為 BookShipment 的類,其中包含兩個屬性,即 ShipmentType 和 Book 類。
public class BookShipment
{
public ShipmentType Shipment { get; set; }
public Books Book { get; set; }
}
我試圖創建一個 where 表達式如下。
Expression<Func<BookShipment, bool>> expr = x => (x.Shipment.ID == 1 && x.Book.ID == 1);
var result = from c in styp
join d in book
on c.ID equals d.ID
select new BookShipment { Shipment = c, Book = d };
var List = result.Where(expr).ToList();
和上述 where 子句的表達式工作正常並從數據庫中獲取結果。
試圖創建一個與上述 expr 表達式相同的動態表達式,但它給出了錯誤。
BookShipment table = new BookShipment();
table.Shipment = new ShipmentType();
table.Book = new Books();
ParameterExpression ParameterL = Expression.Parameter(table.GetType(), "x");
ParameterExpression Parameter1 = Expression.Parameter(table.Shipment.GetType(), "x.Shipment");
ParameterExpression Parameter2 = Expression.Parameter(table.Book.GetType(), "x.Book");
var Property1 = Expression.Property(Parameter1, "ID");
var Property2 = Expression.Property(Parameter2, "ID");
var Clause1 = Expression.Equal(Property1, Expression.Constant(1));
var Clause2 = Expression.Equal(Property2, Expression.Constant(1));
var Lambda1 = Expression.Lambda<Func<ShipmentType, bool>>(Clause1, Parameter1);
var Lambda2 = Expression.Lambda<Func<Books, bool>>(Clause2, Parameter2);
var OrElseClause = Expression.Or(Lambda1.Body, Lambda2.Body);
var Lambda = Expression.Lambda<Func<BookShipment, bool>>(OrElseClause, ParameterL);
var result = from c in styp
join d in book
on c.ID equals d.ID
select new BookShipment { Shipment = c, Book = d };
var record = result.Where(Lambda).ToList();
在執行上述 Where 子句時,它給出了錯誤。
{System.InvalidOperationException: The LINQ expression 'DbSet<ShipmentType>
.Join(
outer: DbSet<Books>,
inner: s => s.ID,
outerKeySelector: b => b.BookID,
innerKeySelector: (s, b) => new TransparentIdentifier<ShipmentType, Books>(
Outer = s,
Inner = b
))
.Where(ti => ti.Shipment.ID == 1 || ti.Book.BookID == 1)' could not be translated.
創建表達式以傳遞到 LINQ where 函數時,請注意以下提示:
類型是Expression<Func<T,Bool>>
...
這意味着你有一個 T 類型的參數,你返回一個布爾值
如果您使用這種類型創建兩個 Lambda,並且您想將它們組合起來……即使您具有相同的類型 T 作為參數,這兩個參數實例也不相同……您將不得不遍歷樹並替換參數所以只有一個實例...
如果你想要一個示例代碼......給你......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace SoExamples.ExpressionTrees
{
class Program
{
static void Main(string[] args)
{
var expr1 = GetExpression<Func<A, bool>>(x => x.Prop1 == 42);
var expr2 = GetExpression<Func<A, bool>>(x => x.Prop2 == "foo");
var expr3 = GetConstComparison<A, int>("Prop3.Prop1", 123);
var test = new A { Prop1 = 42, Prop2 = "foo", Prop3 = new B { Prop1 = 123 } };
var f1 = expr1.Compile();
var t1 = f1(test);
var f2 = expr2.Compile();
var t2 = f2(test);
var f3 = expr3.Compile();
var t3 = f3(test);
Expression tmp = Expression.AndAlso(Expression.AndAlso(expr1.Body, expr2.Body), expr3.Body);
tmp = new ParamReplaceVisitor(expr2.Parameters.First(), expr1.Parameters.First()).Visit(tmp);
tmp = new ParamReplaceVisitor(expr3.Parameters.First(), expr1.Parameters.First()).Visit(tmp);
var expr4 = Expression.Lambda<Func<A, bool>>(tmp, expr1.Parameters.First());
var f4 = expr4.Compile();
var t4 = f4(test);
var list = new List<A> { test };
var result = list.AsQueryable().Where(expr4).ToList();
}
static Expression<TDelegate> GetExpression<TDelegate>(Expression<TDelegate> expr)
{
return expr;
}
static Expression<Func<T, bool>> GetConstComparison<T, P>(string propertyNameOrPath, P value)
{
ParameterExpression paramT = Expression.Parameter(typeof(T), "x");
Expression expr = getPropertyPathExpression(paramT, propertyNameOrPath.Split('.'));
return Expression.Lambda<Func<T, bool>>(Expression.Equal(expr, Expression.Constant(value)), paramT);
}
private static Expression getPropertyPathExpression(Expression expr, IEnumerable<string> propertyNameOrPath)
{
var mExpr = Expression.PropertyOrField(expr, propertyNameOrPath.First());
if (propertyNameOrPath.Count() > 1)
{
return getPropertyPathExpression(mExpr, propertyNameOrPath.Skip(1));
}
else
{
return mExpr;
}
}
}
public class ParamReplaceVisitor : ExpressionVisitor
{
private ParameterExpression orig;
private ParameterExpression replaceWith;
public ParamReplaceVisitor(ParameterExpression orig, ParameterExpression replaceWith)
{
this.orig = orig;
this.replaceWith = replaceWith;
}
protected override Expression VisitParameter(ParameterExpression node)
{
if (node == orig)
return replaceWith;
return base.VisitParameter(node);
}
}
public class A
{
public int Prop1 { get; set; }
public string Prop2 { get; set; }
public B Prop3 { get; set; }
}
public class B
{
public int Prop1 { get; set; }
}
}
當然你會想要添加錯誤處理等......
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.