LINQ到实体通用==解决方法

时间:2011-10-27 13:44:55

标签: c# entity-framework entity-framework-4 linq-to-entities

我有以下LINQ到实体查询

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<T>的实体集合。

问题是代码无法编译,因为内部查询中的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中的泛型进行相等比较?

4 个答案:

答案 0 :(得分:1)

试试这个,我认为它应该在没有额外查询/加入的情况下完成你想要的东西

IQueryable<History<T>> GetFirstOperationsForEveryId<T>
    (IQueryable<History<T>> ItemHistory)
{
  var q = from h in ItemHistory
          group h by h.GenericId into tt
          let first = (from t in tt
                        orderby t.GenericId
                        select t).FirstOrDefault()
          select first;

  return q;
}

答案 1 :(得分:0)

IQueryable<History<T>> GetFirstOperationsForEveryId<T>
(IQueryable<History<T>> ItemHistory)
{
var grouped = (from h1 in ItemHistory
               group t 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;
}

答案 2 :(得分:0)

您还可以为实现GenericId和OperationId属性的Item History接口设置T的通用约束。

答案 3 :(得分:0)

我的问题已经包含一个解决方案。如果表已正确编入索引,则使用group + join的第二种方法效果很好。从数据库表中检索370k行需要3.28秒。事实上,在非泛型变体中,postgresql上的第一个查询比第二个查询慢。 26.68秒vs 4.75。