c# – 将lambda参数传递给include语句
我正在使用System.Data.Entity命名空间,因此我可以将lambda表达式传递给
Linq Include方法.
public ICollection<MyEntity> FindAll() { using (var ctx = new MyEntityContext()) { return ctx.MyEntity.Include(x => x.SomeLazyLoadedValue).ToList(); } } 当我在一个不同的方法中使用Where语句时,我可以像这样传递一个参数: public ICollection<MyEntity> FindAllBy(Func<MyEntity,bool> criteria) { using (var ctx = new MyEntityContext()) { return ctx.MyEntity.Where(criteria).ToList(); } } 但是,在Include中尝试相同的操作不起作用: public ICollection<MyEntity> FindAll(Func<MyEntity,bool> criteria) { using (var ctx = new MyEntityContext()) { return ctx.MyEntity.Include(criteria).ToList(); } } 如果你试试这个,Visual Studio会抱怨它 Cannot convert from 'System.Func<MyEntity,bool>' to 'string' 如何将lambda传递给Include方法? 解决方法
您的代码存在一些问题.例如,您的FindAllBy不执行sql WHERE查询,而是加载数据库中的所有条目,然后根据您的条件筛选内存中.要理解为什么会这样,请看下面的内容:
int a = 5; long b = 5; 现在,很明显这里发生了什么,但它仍然非常重要.编译器读取以下代码并生成两个变量.一个整数和一个长整数,两者的值都设置为数字5.但是,这两个数字的值是不同的,即使它们(在源代码中)设置为相同的东西.一个是32位,另一个是64位. 现在,我们来看看以下代码: Func<int,string> a = num => num.ToString(); Expr<Func<int,string>> b = num => num.ToString(); 这里发生了同样的事情(或多或少).在第一种情况下,C#编译器看到你想要一个谓词(一个Func< int,string>谓词),而第二个值是一个Expr< Func< int,string>>即使值写得相同.然而,与第一个例子相反,这里的最终结果大不相同. 谓词被编译为编译器生成的类的方法.它的编译方式与其他任何代码一样,只是允许您删除一堆样板.另一方面,表达式是写入的实际代码的内存表示.例如,在这种情况下,表达式可能看起来类似于Call(int.ToString,$1).这可以通过其他代码读取并转换为例如SQL,然后用于查询数据库. 现在,回到你的问题. EntityFramework交给你IQueryable< T>实例,继而继承IEnumerable< T>.每当枚举可枚举时,它都会查询数据库. 接受委托的所有扩展方法都在IEnumerable上定义,因此在运行谓词之前查询数据库.这就是为什么你需要确保选择正确的方法 – 重载. 编辑(回答评论)] Expr<Func<User,bool>> olderThan10 = u => u.Age > 10; Func<User,bool> youngerThan90 = u => u.Age < 90; var users = db.Where(olderThan10).Where(youngerThan90); 这将导致SQL找到所有超过10的用户,之后它会在内存中过滤掉所有早于或等于90的用户. 因此传递Func并不一定意味着它会查询整个数据库.它只是意味着它在该点停止构建查询并执行它. 至于下一个问题,Expression< Func< T,bool>>不是一个普遍的答案.它意味着“一个带有T并返回bool的表达式”.在某些情况下,比如启动整个问题的.Include,你不想返回一个bool.您想要返回任何想要包含的内容.因此,例如,如果我们回到我们的用户示例,并在引用另一个用户的用户类上修改一个Father属性,并且我们想要包含它,那么在常规代码中我们会做 db.Include(u => u.Father); 现在.这里,你是一个用户,返回值u.Father也是一个用户,所以在这种情况下,u => u.Father是Expr< Func< User,User>>或Expr< Func< User,object>> (我不知道实体框架.Include是接受通用值还是简单对象). 所以你的FindAll函数应该看起来像这样: public ICollection<TData> FindAll<TInclude>(Expr<Func<TData,TInclude>> include) { using (var ctx = new TContext()) { return ctx.T.Include(include).ToList(); } } 虽然,老实说,这是非常奇怪的代码,并且你可能会对你的模型做一些奇怪的事情,因为你已经(例如)将它们命名为T和TContext.我的猜测是你需要了解泛型在C#中的工作原理. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |