gpt4 book ai didi

c# - 如何从更小的、可重用的查询中组合 Entity Framework 查询?

转载 作者:太空狗 更新时间:2023-10-29 21:55:37 26 4
gpt4 key购买 nike

我的应用程序中有一些(相当多余的)查询是这样的:

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<int?> FindSeverity(Expression<Func<User, bool>> 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)

我重写了您的最后一个代码片段(以简化形式,没有投影到匿名类型)...

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<Func<Country, T>>正文 ( T 在这种情况下是 int )。 (我不确定“body”是否是正确的 terminus technicus,但你知道我的意思:Lambda 箭头右侧的部分 =>)。当整个查询被翻译成表达式树时,这个主体被翻译为对函数 FindSeverity 的方法调用。 . (当您观察 Expressionquery 属性时,您可以在调试器中看到这一点:FindSeverity 直接是表达式树中的一个节点,而不是此方法的主体。)执行失败,因为 LINQ to Entities不知道这个方法。在这样的 lambda 表达式的主体中,您只能使用已知函数,例如来自静态 System.Data.Objects.EntityFunctions 的规范函数。类。

2)

构建查询的可重用部分的一种可能的通用方法是编写 IQueryable<T> 的自定义扩展方法。 ,例如:

public static class MyExtensions
{
public static IQueryable<int?> FindSeverity(this IQueryable<User> query,
Expression<Func<User, bool>> 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
}

...属于 "Referencing a non-scalar variable" 类别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
}

这不会产生上述引用非标量变量的异常。但也许我误解了你的模型。

关于c# - 如何从更小的、可重用的查询中组合 Entity Framework 查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5782453/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com