如何使匿名方法在LINQ to Entities中运行
本文关键字:to Entities 运行 LINQ 何使匿 方法 | 更新日期: 2023-09-27 17:59:57
我正在尝试构建一个通用方法EF4.1,以便在数据库和本地内存中查找表中符合特定条件的特定行。
到目前为止,这就是我所拥有的。
这是来电者。
dbEntities.MyTables.LocalAndDb(delegate(MyTable s)
{ return s.Description.Contains("test"); });
这是LocalAndDb
public static object LocalAndDb<T>(this DbSet<T> myTable, Func<T, bool> function) where T : class
{
// look in local
var item = myTable.Local.Where(o => function((T)o)).FirstOrDefault()
// if not exist, look in the database
if (item == null)
{
Expression<Func<T, bool>> predicate = (u) => function(u);
item = myTable.Where(predicate).FirstOrDefault();
}
return item;
}
问题出在这条线路上。
item = myTable.Where(predicate).FirstOrDefault();
当它调用数据库时,会抛出此错误。
"LINQ to Entities中不支持LINQ表达式节点类型"Invoke"。"
我想这是因为我传入了一个匿名方法,它不知道如何将其转换为SQL。我原以为把它转换成Expression对象就可以了,但它对我来说仍然不起作用
我需要做些什么才能使匿名方法成为LINQ可以转换为SQL的方法?
要实现这一点,您需要将lambda表达式作为表达式树传递给LocalAndDb
(这样LINQ To Entities就可以分析代码并将其转换为SQL):
public static object LocalAndDb<T>(this DbSet<T> myTable,
Expression<Func<T, bool>> expr) where T : class {
// ...
if (item == null) {
item = myTable.Where(expr).FirstOrDefault();
}
return item;
}
当然,问题是在检查内存中的数据时无法执行表达式树。解决这个问题的一种方法是使用Expression<T>
的Compile
方法,但这会有点低效(取决于您的场景)。
另一种选择是将条件同时作为函数和表达式树传递:
public static object LocalAndDb<T>(this DbSet<T> myTable,
Func<T, boo> function, Expression<Func<T, bool>> expr) where T : class {
var item = myTable.Local.Where(o => function((T)o)).FirstOrDefault();
if (item == null) {
item = myTable.Where(expr).FirstOrDefault();
}
return item;
}
table.LocalAndDb(t => t.Foo > 10, t => t.Foo > 10);
这有点难看,但不需要在运行时进行低效编译。如果你想要一个稍微复杂一点的解决方案,那么你可以定义自己的类型来保留预编译的函数:
class Precompiled<T1, T2> {
public Precompiled(Expression<Func<T1, T2>> expr) {
this.Expression = expr;
this.Function = expr.Compile();
}
public Expression<Func<T1,T2>> Expression { get; private set; }
public Func<T1,T2> Function { get; private set; }
}