Linq:如何针对关联对象使用规约

6

我在使用这种形式的规范:

public static Expression<Func<User, bool>> IsSuperhero
{
  get
  {
    return x => x.CanFly && x.CanShootLasersFromEyes;
  }
}

现在我可以在表单中使用这个规范:

var superHeroes = workspace.GetDataSource<User>().Where(UserSpecifications.IsSuperhero);

但是我不确定如何针对这样的相关对象使用规范:

var loginsBySuperheroes = workspace.GetDataSource<Login>().Where(x => x.User [ ??? ]);

有没有一种方法可以做到这一点,或者我需要重新考虑我的规范实现?
4个回答

4
基本上,您需要创建一个Expression<Func<Login,bool>>,该表达式从Login中收集关联的User,然后在该用户上应用现有的IsSuperhero谓词。实现这一目标的规范方法是在“包含”的表达式(此处为IsSuperHero)上使用Expression.Invoke,将其参数替换为适当的参数。
不幸的是,手动执行此方法相当混乱。更糟糕的是,许多LINQ提供程序(例如LINQ to Entities)根本不喜欢这种“表达式内嵌表达式”的方法。绕过这种方法的方式是将“被调用的”表达式“内联”到更大的表达式中,以便它们看起来像一个单一的、巨大的表达式树。
幸运的是,有一个方便的库LINQKit可以帮助解决这个问题:
#region LINQKit Magic

Expression<Func<Login, bool>> predicate = login => IsSuperHero.Invoke(login.User);
var expandedPredicate = predicate.Expand(); 

#endregion LINQKit Magic

var loginsBySuperheroes = workspace.GetDataSource<Login>().Where(expandedPredicate);

3
显然:
var loginsBySuperheroes = workspace.GetDataSource<User>()
  .Where(UserSpecifications.IsSuperhero)
  .SelectMany(x => x.Logins);

这可能很有趣:

var secretBillionaires = workspace.GetDataSource<User>()
   .Where(UserSpecifications.IsSuperhero)
   .SelectMany(user => user.Logins)
   .Where(LoginSpecifications.IsSecretIdentity)
   .Select(login => login.DayJob)
   .Where(DayJobSpecifications.IsBillionaire)

我认为短期内按照描述重新排列Linq查询可能是对我最好的答案。然而,我一定会查看Ani推荐的LinqKit库。 - David

0

我相信你需要编译并调用这个表达式:

var loginsBySuperheroes = GetLogins().Where(l => IsSuperhero.Compile().Invoke(l.User));

另一种选择可能是预编译表达式:

var f = IsSuperhero.Compile();
var loginsBySuperheroes = GetLogins().Where(l => f(l.User));

这在lin2entity中不起作用,而且在正常情况下也太耗时了。 - Saeed Amiri
原问题中有提到Linq2Entities吗?没有。不确定为什么它不能工作-为什么呢?你所说的“耗时”是什么意思? - samjudson
我认为GetDataSource意味着OP使用了linq2entities(只是猜测),而且由于时间消耗,在想要执行原始查询时,编译和调用一个表达式一次是很耗时的。如果将其用作正常表达式,所有这些表达式都将被解析为一个表达式,并且将执行一次。 - Saeed Amiri
其实这是Linq 2 Sql,但我没有意识到这很重要。使用Compile()会不会意味着规范不会被转换为SQL? - David
也许是这样,是的。恐怕另一种选择(尝试将表达式的整个表达式传递到 linq2sql 查询引擎)超出了我的知识范围。也许 LinqKit 魔法帖子会更好。 - samjudson
这在LINQ2SQL(以及EF)中不起作用,必须使用LINQKit。 - Mic

0

@DavidB - 你说得对,这个答案与问题无关。我分析错了。谢谢你的评论。 - Polity

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