2009-10-09 61 views
3

我想链接多个编译LINQ查询在一起。我成功地将两个查询链接在一起,但我无法获得三个正确的工作链。所以这里是减少我的代码重新创建问题。我的两个问题是:'为什么这不起作用?'和'是否有更好的方法来保持已编译查询的性能优势,并避免重复使用常用的基本查询逻辑?可以将多个已编译的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 上下文在TestMethod的()中 ,对象[]参数)在 System.Data.Linq.CompiledQuery.Invoke(TArg0 为arg0,TArg1 ARG1)....

+0

随时恢复它,但我可以忍受不得不滚动一行。 – 2009-10-09 14:24:40

回答

3

看起来您需要在执行第二个查询之前将您的第一个已编译查询转换为列表。在理论上,这也应该导致你的两个查询链出现错误。

MSDN CompiledQuery

如果一个新的查询运算符应用于委托执行的结果,产生一个异常。

当您想要对执行编译查询的结果执行查询操作符时,必须先将结果转换为列表,然后再对其进行操作。

也许这段代码可以修复它,尽管如果你使用LINQ to SQL,这可能会影响到往返数据库。

filterUserName(dc, name).ToList().Where(user=>user.GroupId == groupId) 
+0

AsEnumerable()就足够了,不需要调用ToList()...除了保存大量不需要的内存复制,如果你使用AsEnumerable()而不是使用ToList() – 2009-10-09 15:09:58

+0

哇,我甚至没有考虑过可能存在L2S允许构建,编译和执行甚至不支持的查询的错误。这让我很震惊,因为链接两个已编译的查询实际上会返回正确的结果。我想接受这个答案,但是我想知道它究竟是如何起作用的? – 2009-10-09 16:21:29

+1

如果使用AsEnumerable()或.ToList(),它将不会动态构建SELECT语句。它会将数据放在第一个.ToList()上,然后在内存中而不是在服务器上执行查询的请求。 – 2009-10-09 17:10:56

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 
} 

上面当然是一个简单的例子。但是,当基于用户输入(例如网站上的“高级搜索”表单)将不同查询组合在一起时,它可能非常有用。

+0

= = 你忘了这些 – 2009-10-12 08:56:58

+0

糟糕!谢谢... – Matt 2009-10-12 12:48:54

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而不是Func <>代表的普通实例方法。

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 
    } 
} 
+0

由于性能要求,使用已编译的查询对于我的应用程序至关重要......您在此处提供的方法是使用重新使用查询(如乐高件)的非常好的方式,但不幸的是,您不能在函数上使用编译查询,只能在表达式。 – 2009-10-09 16:18:10

+0

您是否将我上面的Func <>的性能与您的CompiledQuery版本进行了比较?您可以使用秒表检查执行时间。 http://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch.aspx – 2009-10-09 17:05:48

+0

此外......性能无关紧要,如果它不会运行。 – 2009-10-09 17:12:00

相关问题