Can I dynamically build a where clause in LINQ to Entities?
I'm trying to dynamically build a LINQ query for LINQ to Entities so that I can av开发者_开发百科oid repeating the same function twice.
Here is what I'm trying to do:
private IUser GetOrUpdateUser(Predicate<IUser> filter, Func<IIdentityProvider, UserRecord> fetch)
{
var user = (from u in this.adapter.Users
where filter(u)
select u).SingleOrDefault();
if (user == null)
{
// User not found. Add him.
user = this.adapter.AddUser(fetch(this.idenityProvider));
}
else if (user.IsExpired)
{
// User found, but expired. Update him.
this.adapter.UpdateUser(user, fetch(this.idenityProvider));
}
return user;
}
protected IUser GetUserByNetworkId(string username)
{
return GetOrUpdateUser(
u => u.NetworkId == username,
i => i.GetUserByNetworkId(username));
}
protected IUser GetUserByEmail(string email)
{
return GetOrUpdateUser(
u => u.Email == email,
i => i.GetUserByEmail(email));
}
The filter
parameter is throwing this exception:
The LINQ expression node type 'Invoke' is not supported in LINQ to Entities
I could potentially do this:
protected IUser GetUserByNetworkId(string username)
{
return GetOrUpdateUser(
from u in this.adapter.Users
where u.NetworkId == username
select u,
i => i.GetUserByNetworkId(username));
}
protected IUser GetUserByEmail(string email)
{
return GetOrUpdateUser(
from u in this.adapter.Users
where u.Email == email
select u,
i => i.GetUserByEmail(email));
}
But, that is not as clean.
Any suggestion?
You can combine the two LINQ syntaxes:
private IQueryable<IUser> BuildQuery(IQueryable<IUser> users, string userName)
{
users = users.Where(u => u.UserName == userName);
return users;
}
Then when you call it:
var query = from u in this.BuildQuery(this.adapter.Users, userName)
select u;
Hopefully this will point you in the right direction!
You can do this, but you need to use, e.g., Expression<Func<...
, not just Func<...
.
Expression<Func<User, Bool>> MakePredicate(int id)
{
return u => u.Id == id;
}
void DoStuff()
{
Expression<Func<User, Bool>> pred = MakePredicate(123);
User u = Context.Users.Where(pred).Single()
}
Note that interfaces won't translate to L2E. So you must use User
, not IUser
(or the like).
There are two notable projects on this.
- LINQ Expression Builder, and
- LinqPad's LinQkit which is open source. The PredicateBuilder class demonstrates how to build Linq Query expressions on the Fly.
these references might guide you.
For your immediate use, I suggest Predicatebuilder.
精彩评论