具有联合和编译查询的LINQ-to-SQL“成员访问不合法类型”异常

时间:2010-07-08 15:23:20

标签: linq-to-sql union compiled-query linq.compiledquery

我有多个想要联合在一起的查询,然后编译整个事情。未编译的查询运行正常,但“InvalidOperationException:'UserQuery + Foo'的成员访问'Int32 Id'在类型'System.Linq.IQueryable`1 [UserQuery + Foo]上不合法。”编译并运行相同的查询时抛出异常。

我该如何解决这个问题?

void Main()
{
    var db = new MyDataContext( "..." );

    Expression < Func < DataContext, int, IQueryable < Foo > > > queryExpression = (DataContext dc, int unused) =>
        from ab in GetA(dc).Union( GetB(dc) )
        group ab by new { ab.Id, ab.Name } into grp
        select new Foo
        {
            Id = grp.Key.Id,
            Name = grp.Key.Name,
            Total = grp.Count()
        };

    var final = CompiledQuery.Compile ( queryExpression );

    var result1 = queryExpression.Compile () (db, 0);  // calling the original query works fine
    var result2 = final (db, 0);            // calling the compiled query throws an exception
}

public class Foo
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Total { get; set; }
}

IQueryable<Foo> GetA( DataContext db )
{
    return from b in db.GetTable<Bar>()
    where b.IsActive
    select new Foo { Id = b.Id, Name = b.Name };
}

IQueryable<Foo> GetB( DataContext db )
{
    return from b in db.GetTable<Bar>()
    where !b.IsActive
    select new Foo { Id = b.Id, Name = b.Name };
}

修改

看起来联盟和分组是无关紧要的。从查询中删除这些元素仍然会在编译时导致异常:

    Expression < Func < DataContext, int, IQueryable < Foo > > > queryExpression = (DataContext dc, int unused) =>
        from a in GetA(dc)
        select new Foo
        {
            Id = a.Id,
            Name = a.Name,
            Total = 42
        };

GetA(dc)的调用替换为dc.GetTable<Bar>()并添加where子句可以解决问题。

那么,是否将单独的查询连接在一起,就像编译查询一样,这是不可能的?

编辑#2

詹姆斯的回答击中了头部。简化查询甚至可以进一步揭示根本问题:

    Expression < Func < DataContext, int, IQueryable < Foo > > > queryExpression = (DataContext dc, int unused) =>
        from a in GetA(dc)
        select a;

此查询会抛出NotSupportedException: Method 'System.Linq.IQueryable``1[UserQuery+Foo] GetA(System.Data.Linq.DataContext)' has no supported translation to SQL.

将对GetA的调用拉入单独的变量赋值,然后在查询中使用该变量会引发InvalidOperationException: Sequence contains more than one element异常。

2 个答案:

答案 0 :(得分:0)

我的猜测是linq编译器不理解返回IQueryable的方法。

要编译它,这些方法可能必须返回某种形式的Expression&lt;&gt;。

答案 1 :(得分:0)

我遇到了同样的问题,似乎对我来说诀窍是分离出一个返回IQueryable&lt;&gt;的内联静态方法调用。所以我将这个延迟查询存储到一个变量并引用它。

我认为这是Linq to SQL中的一个错误,但至少有一个合理的解决方法。