如何从较小的可重复使用的查询中编写entity framework查询?
我在我的应用程序中有一些(相当多余的)查询,如下所示:
var last30Days = DateTime.Today.AddDays(-30); from b in Building let issueSeverity = (from u in Users where u.Building == b from i in u.Issues where i.Date > last30Days select i.Severity).Max() select new { Building = b, IssueSeverity = issueSeverity }
和:
var last30Days = DateTime.Today.AddDays(-30); from c in Countries let issueSeverity = (from u in Users where u.Building.Country == c from i in u.Issues where i.Date > last30Days select i.Severity).Max() select new { Country = c, IssueSeverity = issueSeverity }
当然,这是一个简化的例子。 但是,要点是我需要捕获一个日期并在其上过滤子查询。 我还需要根据父对象以不同方式过滤子查询。
我(基本上)尝试创建以下函数:
public IQueryable FindSeverity(Expression<Func> predicate) { var last30Days = DateTime.Today.AddDays(-30); return from u in Users.Where(predicate) from i in u.Issues where i.Date > last30Days select i.Severity; }
使用方法如下:
from c in Countries let issueSeverity = FindSeverity(u => u.Building.Country == c).Max() select new { Country = c, IssueSeverity = issueSeverity }
这会编译,但在运行时不起作用。 entity framework抱怨FindSeverity
函数未知。
我尝试了几种不同的表现体操方法,但无济于事。
构建可重用的Entity Framework查询需要做什么?
我已经玩了一些你的问题,但没有最终令人满意的结果。 我只列出我能找到并理解的几点。
1)
我重写了你的最后一个代码片段(简化forms,没有投影到匿名类型)…
var query = from c in Countries select FindSeverity(u => u.Building.Country == c).Max();
…然后在扩展方法语法中:
var query = Countries .Select(c => FindSeverity(u => u.Building.Country == c).Max());
现在我们更好地看到FindSeverity(u => u.Building.Country == c).Max()
是Expression
的主体 (在这种情况下T
是int
)。 (我不确定“身体”是否是正确的终点技术,但你知道我的意思:正确的部分来自Lambda箭头=>)。 当整个查询被翻译成表达式树时,该主体被翻译为对函数FindSeverity
的方法调用。 (当您查看query
的Expression
属性时,您可以在调试器中看到这一点: FindSeverity
直接是表达式树中的一个节点,而不是此方法的主体。)执行失败,因为LINQ to Entities不知道此方法。 在这种lambda表达式的主体中,您只能使用已知函数,例如静态System.Data.Objects.EntityFunctions
类中的规范函数。
2)
构建查询的可重用部分的一种可能的一般方法是编写IQueryable
自定义扩展方法,例如:
public static class MyExtensions { public static IQueryable FindSeverity(this IQueryable query, Expression> predicate) { var last30Days = DateTime.Today.AddDays(-30); return from u in query.Where(predicate) from i in u.Issues where i.Date > last30Days select i.Severity; } }
然后你可以编写如下查询:
var max1 = Users.FindSeverity(u => u.Building.ID == 1).Max(); var max2 = Users.FindSeverity(u => u.Building.Country == "Wonderland").Max();
如您所见,您被迫以扩展方法语法编写查询。 我没有看到在查询语法中使用此类自定义查询扩展方法的方法。
上面的示例只是创建可重用查询片段的一般模式,但它对您问题中的特定查询没有实际帮助。 至少我不知道如何重新制定你的FindSeverity
方法,以便它适合这种模式。
3)
我相信您的原始查询无法在LINQ to Entities中运行。 像这样的查询……
from b in Building let issueSeverity = (from u in Users where u.Building == b from i in u.Issues where i.Date > last30Days select i.Severity).Max() select new { Building = b, IssueSeverity = issueSeverity }
…属于LINQ to Entities不支持的查询内部的“引用非标量变量”类别。 (在它工作的LINQ to Objects中。)上面查询中的非标量变量是Users
。 如果Building
表不为空,则需要例外: “无法创建EntityType类型的常量值。在此上下文中仅支持基本类型(例如Int32,String和Guid’)。”
看起来您在数据库中的User
和Building
之间存在一对多关系,但此关联未在您的实体中完全建模: User
具有导航属性Building
但Building
没有Users
集合。 在这种情况下,我希望在查询中Join
一个类似于:
from b in Building join u in Users on u.Building.ID equals b.ID let issueSeverity = (i in u.Issues where i.Date > last30Days select i.Severity).Max() select new { Building = b, IssueSeverity = issueSeverity }
这不会创建引用非标量变量的上述exception。 但也许我误解了你的模型。
上述就是C#学习教程:如何从较小的可重复使用的查询中编写entity framework查询?分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/1018433.html