patterncsharpMinor
EF IQueryable Extension Methods
Viewed 0 times
methodsiqueryableextension
Problem
I've started building extension methods for my EF classes like below because it makes building queries so easy, and the intellisense provided helps keep people from writing a new Where() clause in code every time they do to do something.
Example Extensions to an EF User Class
Examples - "Get all admins named Bob"
Results
The results are comparable with the inline one edging out ahead in speed. It's interesting that the extension-based one used a parameter for the roleID and the inline one did not. That's the only real difference I can see.
I really like the fluent-like style the Extension method provides, and how it encapsulates logic to prevent erroneous queries from being written (like forgetting to
Example Extensions to an EF User Class
public static class UserIQX
{
public static IQueryable WhereInSearch(this IQueryable value, string search)
{
search = search.ToLower();
return value.Where(user => user.FirstName.ToLower().Contains(search) || user.LastName.ToLower().Contains(search) || user.EmailAddress.ToLower().Contains(search));
}
public static IQueryable WhereInRole(this IQueryable value, RoleEnum role)
{
return value.Where(user => user.RoleID == (int)role);
}
}Examples - "Get all admins named Bob"
protected void Page_Load(object sender, EventArgs e)
{
var search = "Bob";
//With Extensions
var activeAdmins = db.Users
.WhereInRole(RoleEnum.Admin)
.WhereInSearch(search)
.Select(u => new { EmailAddress = u.EmailAddress })
.ToList();
//Without extensions
search = search.ToLower();
var pq = db.Users
.Where(u => (
u.FirstName.ToLower().Contains(search)
|| u.LastName.ToLower().Contains(search)
|| u.EmailAddress.ToLower().Contains(search))
&& u.RoleID == (int)RoleEnum.Admin)
.Select(u => new { EmailAddress = u.EmailAddress })
.ToList();
}Results
The results are comparable with the inline one edging out ahead in speed. It's interesting that the extension-based one used a parameter for the roleID and the inline one did not. That's the only real difference I can see.
I really like the fluent-like style the Extension method provides, and how it encapsulates logic to prevent erroneous queries from being written (like forgetting to
ToLower() the string fields or something). Is there a good reason why this would be a Really Bad Idea? If not, I Solution
By moving this question from StackOverflow to here, usr's sensible remarks were lost. I restore them here as community wiki:
No, this is fine and recommended. You'll find a limitation of this approach: You cannot use these extension methods in places where they get turned into an expression:
This does not work because EF does not know the
The
Using the same approach you should be able to inline constants such as the role ID into the query as well.
Note, that the design of
No, this is fine and recommended. You'll find a limitation of this approach: You cannot use these extension methods in places where they get turned into an expression:
db.Something.Any(x => x.Users.WhereInRole(RoleEnum.Admin))This does not work because EF does not know the
WhereInRole method.The
AsExpandable extension method can help with this. Search the web to find it as a small library.Using the same approach you should be able to inline constants such as the role ID into the query as well.
Note, that the design of
WhereInRole is not really ideal. Normally, you'd write a method bool IsUserInRole(User, int). No need to operate on sequences at all. The only reason this is not possible here is that you need to find a way to marshal the filtering logic into the final expression tree. Shoving the logic into the argument to Where is a hack to do that. This issue/concern is a "dirty secret" of LINQ. It's quite hacky and arbitrary.Code Snippets
db.Something.Any(x => x.Users.WhereInRole(RoleEnum.Admin))Context
StackExchange Code Review Q#117652, answer score: 3
Revisions (0)
No revisions yet.