开发者

Modularize (refactor) Linq queries

I have a few Linq queries. Semantically, they are

  1. a join b join c join d where filter1(a) && filter2(c) && filter3(d)

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

  3. a join b join c join e where filter1(a) && filter2(c) && filter4(e)

...

I want to be able to factor out the shared part:

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

and dynamically append join d and filter3(d)

Is there a way to do this? I am already using the Predicate Builder to dynamically build conditionals (filters).

EDIT: I am using Linq-to-SQL.

EDIT: The base query looks like:

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 { ... }

filters are predicates in Predicate Builder. The type of the query is IQueryable<A>.

Next, I'd like 开发者_Go百科to join this with d

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

Currently join d .. causes a compilation error:

The type of one of the expressions in the join clause is incorrect. Type inference failed in the call to Join


Your example is a bit vague, but it is easy to create a method that returns an IQueryable<T> and reuse that method, if that’s what you mean. Here is an example:

// 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;
}

You can reuse this method in other places like this:

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

Because the way IQueryable works, only the final query (the collection that you start iterating) will trigger a call to the database, which allows you to build a highly maintainable system by reusing business logic that gets effectively executed inside the database, whiteout the loss of any performance.

I do this all the time and it improves the maintainability of my code big time. It works no matter which O/RM tool you run, because there is no difference in Queryable<T> composition, between writing the query in one peace, or splitting it out to different methods.

Note that you do sometimes need some smart transformations to get the duplicate parts in a single method. Things that might help are returning grouped sets, and returning a set of a different type, than what you think you need. This sounds a bit vaque, but just post a question here at SO when you have problems splitting up a method. There are enough people here that can help you with that.


I can answer half your question easily. Linq makes it simple to append .where clauses to an existing query.

Example:

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

I believe you can do the joins as well but I have to go find an example in some old code. I'll look if nobody else jumps in with it soon.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜