如何解决实体框架核心:使用计算字段进行分组
我正在尝试编写查询。我到目前为止所拥有的如下所示。
var x = from d in DbContext.StorageDetails
let state = (d.ReleaseDate.HasValue && d.ReleaseDate < date) || (d.TakeOrPayEndDate.HasValue && d.TakeOrPayEndDate < date) ?
StorageState.Closed :
(d.RailcarNumber == null || d.RailcarNumber == string.Empty) ?
d.TakeOrPayStartDate.HasValue ? StorageState.TakeOrPay : StorageState.Open :
(d.ArrivalDate.HasValue && d.ArrivalDate <= date) ? StorageState.Filled : StorageState.EnRoute
group d by new
{
d.CustomerId,d.Customer.Name,d.LocationId,d.Location.City,d.Location.State
} into g
select new
{
// ...
};
给我带来麻烦的部分是,我想在每个项目中包含计算出的state
值。我不想按此值分组,但我希望能够对其求和。
// Note: This is after my group statement
select new
{
// state is a let variable and not part of x!
TotalOpen = g.Sum(x => x.state == StorageState.Open),TotalClosed = g.Sum(x => x.state == StorageState.Closed),// Etc.
};
有没有办法做到这一点?我似乎无法select
之前group by
自己的一组列。如何将计算所得的字段插入每个项目?
注意:StorageState
是一个枚举。在所有这些表达式中,我都可以轻松地将其转换为int
。我可以弄清楚那部分,但是弄清楚这和我的问题是分开的。
解决方法
那呢:
TotalOpen = g.Sum(x => (x.ReleaseDate.HasValue && x.ReleaseDate < date) || (x.TakeOrPayEndDate.HasValue && x.TakeOrPayEndDate < date) ?
StorageState.Closed :
(x.RailcarNumber == null || x.RailcarNumber == string.Empty) ?
x.TakeOrPayStartDate.HasValue ? StorageState.TakeOrPay : StorageState.Open :
(x.ArrivalDate.HasValue && x.ArrivalDate <= date) ? StorageState.Filled : StorageState.EnRoute
== StorageState.Open? 1 : 0)
您将重复整个表达式四次。
,我不知道您将如何将其编写为查询表达式,也不知道EF是否可以将该表达式转换为sql。我会做类似下面的事情;
var query = ....
// Select all the values you need
.Select(d => new {
d.CustomerId,d.Customer.Name,d.LocationId,d.Location.City,d.Location.State,....
state = [insert expression]
})
// group by this key
.GroupBy(d => new {
d.CustomerId,d.Name,d.City,d.State
},// and define the final result set
(d,g) => new {
d.CustomerId,d.State,TotalOpen = g.Sum(x => x.state == StorageState.Open ? 1 : 0),TotalClosed = g.Sum(x => x.state == StorageState.Closed ? 1 : 0)
});
我认为sql EF会生成,将第一个select放在from子句中,并用典型的select / group by语句包围。
,这里似乎发生了两件事:
-
从
-
DbContext
,以某种方式对找到的每个项目(d
)进行一些处理,以确定state
的值...
为每个 -
d
,然后将所有d
分组,然后仅选择了d
的几个属性...
StorageDetails
中查询state
确定这可能是另一种方法:
var x = DbContext.StorageDetails
.GroupBy(d => new
{
d.CustomerId,d.State
}).Select(d => new
{
d.CustomerId,d.state = getState(d)
}).ToList();
int getState(d)
{
return (d.ReleaseDate.HasValue && d.ReleaseDate < date) || (d.TakeOrPayEndDate.HasValue && d.TakeOrPayEndDate < date) ?
StorageState.Closed :
(d.RailcarNumber == null || d.RailcarNumber == string.Empty) ?
d.TakeOrPayStartDate.HasValue ? StorageState.TakeOrPay : StorageState.Open :
(d.ArrivalDate.HasValue && d.ArrivalDate <= date) ? StorageState.Filled : StorageState.EnRoute;
}
var TotalOpen = x.Count(x => x.state == StorageState.Open),var TotalClosed = x.Count(x => x.state == StorageState.Closed)
基本上,您首先要从数据库对其进行分组。对其进行分组后,您可以选择特定的属性并引入一个名为state
的属性。但是状态的计算是使用另一个函数,该函数从数据库中获取一行,从enum StorageState
返回一个值,就像在问题。然后将结果作为列表返回。
只有在拥有列表之后,才更容易检查返回的行中包含open
或closed
...
现在,您可以进行常规循环并遍历x
并计算TotalClosed
和TotalClosed
。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。