我正在使用实体框架和Linq to Entities。 我创建了一个小型数据库模式和框架来实现版本控制和本地化。 每个实体现在由两个或三个表组成(即Product,ProductBase和ProductLocal)。
我的 linq 始终包含以下样板代码:
from o in DB.Product
from b in o.Base
from l in o.Local
WHERE o.VersionStatus == (int)VersionStatus.Active
&& b.VersionStatus == (int)VersionStatus.Active
&& l.VersionStatus == (int)VersionStatus.Active
&& l.VersionLanguage == Context.CurrentLanguage
select new ProductInstance { Instance = o, Base = b, Local = l }
我想完成的是将上述内容转换为:
(from o in DB.Product
from b in o.Base
from l in o.Local
select new ProductInstance { Instance = o, Base = b, Local = l }).IsActive()
或者最坏的情况是:
from o in DB.Product.Active()
from b in o.Base.Active()
from l in o.Local.Active()
select new ProductInstance { Instance = o, Base = b, Local = l }
我已经扩展了EDM生成的基类,以实现一些强制执行属性的接口(IVersionStatus和/或IVersionLanguage)。 有没有办法可以遍历表达式树,检查表达式中的类型是否实现了该接口,然后相应地设置 VersionStatus?
我喜欢它像第一个选项一样简单,只是少写和/或忘记。 我见过在事后,在IEnumerable之后这样做的例子,但我宁愿不要从数据库中提取比我需要的更多。
感谢您的任何提示!
是的。
您可以通过在IQueryable上定义名为IsActive的扩展方法来执行此操作。IQueryable 上有一个名为"表达式"的属性,它返回一个表达式树,该表达式树表示从查询生成的 LINQ 方法调用链。
在您的情况下,它看起来像这样:
DB.Product.SelectMany(o=>o.base, (o, b)=>new{o.b}).SelectMany(item=>o.local, (item, local)=>new {item.o, item.b, item.local}).Select(item=>new ProductInstance { Instance = item.o, Base = item.b, Local=item.Local});
"数据库.产品"是第一个"发件人"子句中的项目。每个剩余的"SelectMany"调用都是一个附加的 from 子句。
然后,您可以深入了解表达式树以收集所有 from 子句元素。 查看它们的类型,然后最终为 where 子句生成表达式树。
然后,您的扩展方法将返回 .哪里是 IQueryable 参数,使用您生成的 where 子句。
然后,当您尝试"foreach"结果时,生成的 Where 子句将与查询的其余部分一起在服务器上执行。
编辑:
请注意,如果您希望它与显式"Join"子句一起使用,那么除了"SelectMany"之外,您还需要添加对"Join"方法的支持。
您需要使用 DataLoadOptions 类,以便它自动加载您在该对象上指定的外键关系。这将使它自动获取您指定的链接表,这才是您真正正在做的事情。
此页面详细介绍了如何做到这一点,并详细介绍了我认为您正在寻找的内容。
http://www.crazysalsadancer.com/2008/08/efficient-data-loading-with-linq-using.html
我可能是错的,但我认为DataLoadOptions
不适用于实体框架。