Entity Framework中Linq如何将Lambda表达式嵌入可重用函数中

3
当使用Linq与Entity Framework查询数据库时,有没有减少重复lambda表达式的方法?例如:
db.Users.FirstOrDefault(x => x.Username == "MM001" && x.Type == 1 && x.IsActive == True && x.ExpiryDate > DateTime.Now);

我希望将其简化为:
db.Users.FirstOrDefault(x => x.Username == "MM001" && x.IsActiveStaff());

我尝试将以下方法写入我的用户POCO中:

public bool IsActiveStaff()
{
    return Type == 1 && IsActive == True && ExpiryDate > DateTime.Now;
}

然而,我得到了以下错误:LINQ to Entities不识别“Boolean IsActiveStaff()”方法,也无法将此方法转换为存储表达式。
我意识到这是因为LINQ To Entities无法将此方法转换为SQL表达式,但是有没有办法让它正常工作?
我知道可以编写一个查询命令类,它只需将用户名作为参数,并在其中放置所有逻辑。 但是,我想知道是否可以将一系列lambda嵌入到方法或扩展方法等中,并在需要时像上面的示例那样使用它们。

为了重复使用选择lambda表达式:https://stackoverflow.com/questions/38766411/how-to-parameterize-a-selector-with-a-function-in-ef-query(此问题具有更高的SEO) - ono2012
2个回答

5

我更喜欢使用扩展方法,例如:

public static class UsersExtensions
{
  public static IQueryable<User> IsActive(this IQueryable<User> u)
  {
    // Should really use UTC
    return u.Where(x=>x.IsActive && x.ExpiryDate>DateTime.Now);
  }
  public static IQueryable<User> IsStaff(this IQueryable<User> u)
  {
    return u.Where(x=>x.Type==1);
  }
}

使用方式(带有完整的Intellisense):

var result=db.Users
  .IsActive()
  .IsStaff()
  .FirstOrDefault(x=>x.UserName=="MM001");

我没有想过用这种方式来做。我已经将另一个答案标记为正确,因为它最接近回答我的问题,但我更喜欢这种语法。 - Laurence Frost
公正地说,我也喜欢他的回答。简短、简洁,恰好做到了你所要求的。我只是提供了一个替代方案。 - Robert McKee
两种方法都有其适用场合,具体取决于您是仅将过滤器作为“Where”重复使用,还是以其他方式重复使用谓词。 - Jon Hanna

3

创建一个合适类型的表达式:

Expression<Func<User, bool>> IsActiveStaff = x => x.Type == 1 && x.IsActive && x.ExpiryDate > DateTime.Now;

然后:

db.Users.Where(IsActiveStaff).FirstOrDefault(x => x.Username == "MM001");

@JeffDunlop 它甚至无法编译,因为我考虑的是委托而不是表达式。使用表达式将谓词组合成其他谓词是可能的,但在这种情况下更加复杂,不值得。我已经编辑过了,删除了那一部分。 - Jon Hanna

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接