繁体   English   中英

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

[英]Linq: how to use specifications against associated objects

我正在使用这种形式的规格:

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 [ ??? ]);

有没有办法做到这一点,还是我需要重新考虑我的规范实施?

实际上,您需要创建一个Expression<Func<Login, bool>> ,它从Login中收集关联的User,然后在该用户上应用现有的IsSuperhero谓词。 实现此目的的规范方法是在“包含”表达式(本例中为IsSuperHero )上使用Expression.Invoke ,用适当的参数替换其参数。

不幸的是,这种方法手工操作相当混乱。 更糟糕的是,许多LINQ提供程序,例如LINQ to Entities,根本不喜欢这种“表达式内部表达”方法。 解决这个问题的办法是“内联”的“调用”表达成更大的表达,使这一切看起来像一个单一的 ,巨大的,表达树。

Fortuantely,有一个方便的库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);

明显:

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)

我相信你需要编译然后调用表达式:

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

另一种方法是预编译表达式:

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

您可以创建自己的自定义QueryProvider,如下所述: http//msdn.microsoft.com/en-us/library/bb546158.aspx

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM