5

我以这种形式使用规范:

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 回答 4

4

本质上,您需要创建一个Expression<Func<Login, bool>>从登录中收集关联的用户,然后将现有IsSuperhero谓词应用于该用户。实现这一点的规范方法是使用Expression.Invoke“包含”表达式(IsSuperHero在这种情况下),用适当的参数替换其参数。

不幸的是,这种方法手工操作非常麻烦。更糟糕的是,许多 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);
于 2011-11-08T12:50:04.880 回答
2

明显地:

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)
于 2011-11-08T15:29:38.597 回答
0

您可以按照此处的详细说明创建自己的自定义 QueryProvider:http: //msdn.microsoft.com/en-us/library/bb546158.aspx

于 2011-11-08T11:54:01.350 回答
0

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

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

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

var f = IsSuperhero.Compile();
var loginsBySuperheroes = GetLogins().Where(l => f(l.User));
于 2011-11-08T11:54:22.787 回答