Modularize(重构)Linq查询

时间:2011-08-24 14:14:05

标签: c# linq

我有几个Linq查询。从语义上讲,它们是

  1. a join b join c join d where filter1(a)&& filter2(c)&&过滤器3(d)

  2. a join b join c其中filter1(a)&&过滤器2(c)中

  3. a join b join c join e where filter1(a)&& filter2(c)&&过滤器4(e)中

  4. ...

    我希望能够分解共享部分:

    a join b join c where filter1(a) && filter2(c)
    

    并动态追加join dfilter3(d)

    有办法做到这一点吗?我已经在使用Predicate Builder来动态构建条件(过滤器)。

    编辑:我正在使用Linq-to-SQL。

    编辑:基本查询如下:

    from a in As.AsExpandable()
    join b in Bs on a.Id equals b.PId
    join c in Cs on b.Id equals c.PId
    where filter1(a) && filter2(b) && filter3(c)
    select new A { ... }
    

    过滤器是Predicate Builder中的谓词。查询的类型为IQueryable<A>

    接下来,我想加入d

    from a in BaseQuery()
    join d in D on a.Id equals d.PId
    

    目前join d ..会导致编译错误:

      

    join子句中某个表达式的类型不正确。在对Join

    的调用中,类型推断失败

2 个答案:

答案 0 :(得分:3)

您的示例有点模糊,但很容易创建一个返回IQueryable<T>并重用该方法的方法,如果这就是您的意思。这是一个例子:

// Reusable method
public IQueryable<SomeObject> GetSomeObjectsByFilter(Context c)
{
     return
         from someObject in context.SomeObjects
         where c.B.A.Amount < 1000
         where c.Roles.Contains(r => r.Name == "Admin")
         select someObject;
}

您可以在其他地方重复使用此方法:

var q =
    from c in GetSomeObjectsByFilter(context)
    where !c.D.Contains(d => d.Items.Any(i => i.Value > 100))
    select c;

因为IQueryable的工作方式,只有最终查询(您开始迭代的集合)才会触发对数据库的调用,这允许您通过重用有效执行的业务逻辑来构建高度可维护的系统在数据库内,使任何性能的损失变得白茫。

我一直这样做,它提高了代码的可维护性。无论你运行哪种O / RM工具,它都有效,因为在Queryable<T>组合中,在一个和平中写入查询或将其分解为不同的方法之间没有区别。

请注意,有时您需要进行一些智能转换才能在单个方法中获取重复的部分。可能有帮助的事情是返回分组集,并返回一组不同于您认为需要的类型。这听起来有点不透明,但是当你在分割方法时遇到问题时,只需在这里发布一个问题。这里有足够的人可以帮助你。

答案 1 :(得分:1)

我可以轻松回答你的一半问题。 Linq可以很容易地将.where子句追加到现有查询中。

示例:

var x = db.Table1.where(w => w.field1 == nTestValue);
x = x.where(w => w.field2 == nTestValue2);

我相信你也可以进行连接,但我必须在一些旧代码中找到一个例子。我会看看是否有其他人很快就会参与其中。