LINQ-to-SQL“成员访问类型不合法”联合和编译查询的异常
我有多个查询,我想将它们合并在一起,然后编译整个内容。未编译的查询运行正常,但出现“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
};
用 dc.GetTable
替换对 GetA(dc)
的调用并添加 where 子句修复的问题。
那么,对于编译查询来说,像这样将单独的查询连接在一起是不可能的吗?
编辑#2
詹姆斯的回答一语中的。简化查询进一步揭示了根本问题:
Expression < Func < DataContext, int, IQueryable < Foo > > > queryExpression = (DataContext dc, int unused) =>
from a in GetA(dc)
select a;
此查询抛出 NotSupportedException:方法 'System.Linq.IQueryable``1[UserQuery+Foo] GetA(System.Data.Linq.DataContext)' 不支持对 SQL 的转换.
将对 GetA 的调用拉出到一个单独的变量赋值中,然后在查询中使用该变量会引发 InvalidOperationException:序列包含多个元素
异常。
I have multiple queries that I'd like to union together, then compile the entire thing. The uncompiled query runs fine, but an "InvalidOperationException: Member access 'Int32 Id' of 'UserQuery+Foo' not legal on type 'System.Linq.IQueryable`1[UserQuery+Foo]." exception is thrown when the same query is compiled and run.
How do I fix this?
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 };
}
EDIT
It looks like the union and grouping are irrelevant. Removing those elements from the query still causes an exception when compiled:
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
};
Replacing the call to GetA(dc)
with dc.GetTable<Bar>()
and adding the where clause fixes the issue.
So, is connecting separate queries together like this simply not possible for compiled queries?
EDIT #2
James' answer hit the nail on the head. Simplifying the query even further reveals the root problem:
Expression < Func < DataContext, int, IQueryable < Foo > > > queryExpression = (DataContext dc, int unused) =>
from a in GetA(dc)
select a;
This query throws NotSupportedException: Method 'System.Linq.IQueryable``1[UserQuery+Foo] GetA(System.Data.Linq.DataContext)' has no supported translation to SQL.
Pulling the call to GetA out into a separate variable assignment, then using that variable in the query throws a InvalidOperationException: Sequence contains more than one element
exception.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我遇到了同样的问题,似乎对我有用的是分离出一个返回 IQueryable<> 的内联静态方法调用。这样我就把这个延迟查询存储到一个变量中并引用它。
我认为这是 Linq to SQL 中的一个错误,但至少有一个合理的解决方法。
I had the same issue and what seemed to do the trick for me was separating out an inline static method call that returned IQueryable<> so that I stored this deferred query into a variable and referenced that.
I think this is a bug in Linq to SQL but at least there is a reasonable workaround.
我的猜测是 linq 编译器不理解返回 IQueryable 的方法。
为了编译它,这些方法可能必须返回某种形式的 Expression<>。
My guess is that the linq compiler doesn't understand the methods returning IQueryable.
To compile it, those methods would probably have to return some form of Expression<>.