LINQ 到实体通用 == 解决方法
我有一个以下 LINQ-to-entities 查询
IQueryable<History<T>> GetFirstOperationsForEveryId<T>
(IQueryable<History<T>> ItemHistory)
{
var q = (from h in ItemHistory
where h.OperationId ==
(from h1 in ItemHistory
where h1.GenericId == h.GenericId
select h1.OperationId).Min()
select h);
return q;
}
ItemHistory
是一个通用查询。它可以通过以下方式获得
var history1 = MyEntitiySet1.Select(obj =>
new History<long>{ obj.OperationId, GenericId = obj.LongId });
var history2 = AnotherEntitiySet.Select(obj =>
new History<string>{ obj.OperationId, GenericId = obj.StringId });
最后,我希望通用查询能够与可转换为 History
的任何实体集合一起使用。
问题是由于内部查询中的 GenericId 比较,代码无法编译(运算符“==”不能应用于“T”和“T”类型的操作数)。
如果我将 == 更改为 h1.GenericId.Equals(h.GenericId)
我会收到以下 NotSupportedException
:
无法将类型“System.Int64”转换为类型“System.Object”。 LINQ to Entities 仅支持转换实体数据模型基元类型。
我尝试进行分组而不是子查询并加入结果。
IQueryable<History<T>> GetFirstOperationsForEveryId<T>
(IQueryable<History<T>> ItemHistory)
{
var grouped = (from h1 in ItemHistory
group h1 by h1.GenericId into tt
select new
{
GenericId = tt.Key,
OperationId = tt.Min(ttt => ttt.OperationId)
});
var q = (from h in ItemHistory
join g in grouped
on new { h.OperationId, h.GenericId }
equals new { g.OperationId, g.GenericId }
select h);
return q;
}
它可以编译,因为 GenericId 与 equals
关键字进行比较并且它可以工作,但是使用真实数据的查询太慢(它已经在专用的 postgresql 服务器上运行了 11 个小时)。
有一个选项可以为外部 where 语句构建整个表达式。但代码太长而且不清楚。
是否有任何简单的解决方法可以在 LINQ-to-entities 中与泛型进行相等比较?
I have a following LINQ-to-entities query
IQueryable<History<T>> GetFirstOperationsForEveryId<T>
(IQueryable<History<T>> ItemHistory)
{
var q = (from h in ItemHistory
where h.OperationId ==
(from h1 in ItemHistory
where h1.GenericId == h.GenericId
select h1.OperationId).Min()
select h);
return q;
}
ItemHistory
is a generic query. It can be obtained in the following way
var history1 = MyEntitiySet1.Select(obj =>
new History<long>{ obj.OperationId, GenericId = obj.LongId });
var history2 = AnotherEntitiySet.Select(obj =>
new History<string>{ obj.OperationId, GenericId = obj.StringId });
In the end of all I want a generic query being able to work with any entity collection convertible to History<T>
.
The problem is the code does not compile because of GenericId comparison in the inner query (Operator '==' cannot be applied to operands of type 'T' and 'T').
If I change == to h1.GenericId.Equals(h.GenericId)
I get the following NotSupportedException
:
Unable to cast the type 'System.Int64' to type 'System.Object'. LINQ to Entities only supports casting Entity Data Model primitive types.
I've tried to do grouping instead of subquery and join the results.
IQueryable<History<T>> GetFirstOperationsForEveryId<T>
(IQueryable<History<T>> ItemHistory)
{
var grouped = (from h1 in ItemHistory
group h1 by h1.GenericId into tt
select new
{
GenericId = tt.Key,
OperationId = tt.Min(ttt => ttt.OperationId)
});
var q = (from h in ItemHistory
join g in grouped
on new { h.OperationId, h.GenericId }
equals new { g.OperationId, g.GenericId }
select h);
return q;
}
It compiles because GenericId's are compared with equals
keyword and it works but the query with real data is too slow (it has been running for 11 hours on dedicated postgresql server).
There is an option to build a whole expression for the outer where statement. But the code would be too long and unclear.
Are there any simple workarounds for equality comparison with generics in LINQ-to-entities?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
试试这个,我认为它应该可以完成你想要的,而不需要额外的查询/连接
Try this, I think it should accomplish what you want without the extra query/join
您还可以为实现 GenericId 和 OperationId 属性的 IItemHistory 接口设置 T 的通用约束。
You could also set a generic constraint on T for an IItemHistory inteface that implements the GenericId and OperationId property.
我的问题已经包含了解决方案。如果表已正确索引,则使用组+联接的第二种方法效果很好。从数据库表中检索 370k 行需要 3.28 秒。事实上,在非通用变体中,postgresql 上的第一个查询比第二个查询慢。 26.68 秒 vs 4.75 秒。
My question already contains a solution. The second method with group + join works well if the table is properly indexed. It takes 3.28 seconds to retrieve 370k rows from the database table. In fact in non-generic variant the first query is slower on postgresql than the second one. 26.68 seconds vs 4.75.