我正在尝试将多个已编译的linq查询链接在一起。我已经成功地将两个查询链接在一起,但我不能让三个链条正常工作。所以这是减少我的代码来重新创建问题。我的两个问题是:'为什么这不起作用?'并且'是否有更好的方法来保持编译查询的性能优势,并避免重复使用常用的基本查询逻辑?'
定义以下两个查询:
Func<DataContext, IQueryable<User>> selectUsers =
CompiledQuery.Compile(
(DataContext dc)=>dc.Users.Select(x=>x)
);
//
Func<DataContext, string, IQueryable<User>> filterUserName =
CompiledQuery.Compile(
(DataContext dc, string name) =>
selectUsers(dc).Where(user=>user.Name == name)
);
调用和枚举链可以正常工作:
filterUserName(new DataContext(), "Otter").ToList();
向链中添加第三个查询:
Func<DataContext, string, int, IQueryable<User>> filterUserAndGroup =
CompiledQuery.Compile(
(DataContext dc, string name, int groupId) =>
filterUserName(dc, name).Where(user=>user.GroupId == groupId)
);
调用链不起作用:
filterUserAndGroup(new DataContext(), "Otter", 101);
System.InvalidOperationException: 会员访问“用户”的“字符串名称” 在类型上不合法 “System.Linq.IQueryable
1[User].. at System.Data.Linq.SqlClient.SqlMember.set_Expression(SqlExpression value) at System.Data.Linq.SqlClient.SqlFactory.Member(SqlExpression expr, MemberInfo member) at System.Data.Linq.SqlClient.SqlBinder.Visitor.AccessMember(SqlMember m, SqlExpression expo) at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitMember(SqlMember m) at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node) at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitExpression(SqlExpression expr) at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitBinaryOperator(SqlBinary bo) at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node) at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitExpression(SqlExpression expr) at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitSelect(SqlSelect select) at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node) at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitAlias(SqlAlias a) at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node) at System.Data.Linq.SqlClient.SqlVisitor.VisitSource(SqlSource source) at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitSelect(SqlSelect select) at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node) at System.Data.Linq.SqlClient.SqlBinder.Visitor.VisitIncludeScope(SqlIncludeScope scope) at System.Data.Linq.SqlClient.SqlVisitor.Visit(SqlNode node) at System.Data.Linq.SqlClient.SqlBinder.Bind(SqlNode node) at System.Data.Linq.SqlClient.SqlProvider.BuildQuery(ResultShape resultShape, Type resultType, SqlNode node, ReadOnlyCollection
1 parentParameters,SqlNodeAnnotations 注释) System.Data.Linq.SqlClient.SqlProvider.BuildQuery(表达式 查询,SqlNodeAnnotations注释) 在 System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Compile(表达式 查询) System.Data.Linq.CompiledQuery.ExecuteQuery(的DataContext context,Object [] args)at System.Data.Linq.CompiledQuery.Invoke(TArg0 arg0,TArg1 arg1)在TestMethod()中 ....
答案 0 :(得分:3)
在执行第二个编译查询之前,您需要将第一个编译的查询转换为列表。理论上,这也应该导致你的两个查询链出错。
如果将新查询运算符应用于委托执行的结果,则会生成异常。
如果要对执行编译查询的结果执行查询运算符,则必须先将结果转换为列表,然后再对其进行操作。
也许这段代码会修复它,虽然如果你使用的是LINQ to SQL,这可能会对往返数据库产生影响。
filterUserName(dc, name).ToList().Where(user=>user.GroupId == groupId)
答案 1 :(得分:0)
不可否认,我不熟悉CompiledQuery。但是,由于LINQ的延迟执行性质,您可以执行以下操作:
var result = dbContext.Users.Where(user => user.id == id);
result = result.Where(user => user.GroupID == groupID);
result = result.Select(user => user.username);
for(String username in result){
; // do something
}
以上当然是一个简单的例子。但是,当根据用户输入(例如网站上的“高级搜索”表单)将不同的查询组合在一起时,它可能非常有用。
答案 2 :(得分:0)
您需要使用CompiledQuery类吗?试试这个......
static Func<DataContext, IQueryable<User>> selectUsers =
(dc) => dc.Users.Select(x => x);
//
static Func<DataContext, string, IQueryable<User>> filterUserName =
(DataContext dc, string name) =>
selectUsers(dc).Where(user => user.Name == name);
//
static Func<DataContext, string, int, IQueryable<User>> filterUserAndGroup =
(DataContext dc, string name, int groupId) =>
filterUserName(dc, name).Where(u => u.GroupID == groupId);
...测试代码(我知道我的DataContext不是LINQ2SQL,但这是LINQ的乐趣和美丽)......
此外,我对我自己的数据库使用此方法,因此我知道它们构建为单个查询以发送到数据库。我甚至使用了返回IQueryable&lt;&gt;的普通实例方法而不是Func&lt;&gt;代表。
public class DataContext
{
public static Func<DataContext, IQueryable<User>> selectUsers =
(dc) => dc.Users.Select(x => x);
//
public static Func<DataContext, string, IQueryable<User>> filterUserName =
(DataContext dc, string name) =>
selectUsers(dc).Where(user => user.Name == name);
//
public static Func<DataContext, string, int, IQueryable<User>> UsrAndGrp =
(DataContext dc, string name, int groupId) =>
filterUserName(dc, name).Where(u => u.GroupID == groupId);
public DataContext()
{
Users = new List<User>()
{
new User(){ Name = "Matt", GroupID = 1},
new User(){ Name = "Matt", GroupID = 2},
new User(){ Name = "Jim", GroupID = 2},
new User(){ Name = "Greg", GroupID = 2}
}.AsQueryable();
}
public IQueryable<User> Users { get; set; }
public class User
{
public string Name { get; set; }
public int GroupID { get; set; }
}
}
class Program
{
static void Main(string[] args)
{
var q1 = DataContext.UsrAndGrp(new DataContext(), "Matt", 1);
Console.WriteLine(q1.Count()); // 1
var q2 = DataContext.filterUserName(new DataContext(), "Matt");
Console.WriteLine(q2.Count()); // 2
}
}