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

发布于 2024-12-14 06:58:08 字数 539 浏览 3 评论 0 原文

我正在以这种形式使用规范:

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

有没有办法做到这一点,或者我可以这样做吗?需要重新考虑我的规范实施吗?

I'm using specifications in this kind of form:

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

Now I can use this specification in the form:

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

But I'm not sure how to use the specification against an associated object like this:

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

Is there a way to do this, or do I need to rethink my implementation of specifications?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

虚拟世界 2024-12-21 06:58:08

本质上,您需要创建一个 Expression> 来从登录中收集关联的用户,然后对该用户应用现有的 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);

Essentially, you need to create an Expression<Func<Login, bool>> that collects the associated User from a Login and then applies the existing IsSuperhero predicate on that user. The canonical way to accomplish this is to use Expression.Invoke on the 'contained' expression (IsSuperHero in this case), replacing its parameters with appropriate arguments.

Unfortunately, this approach is quite messy to do by hand. Worse, many LINQ providers, such as LINQ to Entities, don't like this sort of 'expression inside an expression' approach at all. The way around this is to 'inline' the 'invoked' expression into the bigger expression so that it all looks like a single, giant, expression-tree.

Fortuantely, there's the handy library LINQKit that can help out with this:

#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);
┾廆蒐ゝ 2024-12-21 06:58:08

显然:

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)

Obviously:

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

This can be fun:

var secretBillionaires = workspace.GetDataSource<User>()
   .Where(UserSpecifications.IsSuperhero)
   .SelectMany(user => user.Logins)
   .Where(LoginSpecifications.IsSecretIdentity)
   .Select(login => login.DayJob)
   .Where(DayJobSpecifications.IsBillionaire)
疧_╮線 2024-12-21 06:58:08

您可以创建自己的自定义 QueryProvider,详细说明如下:http://msdn。 microsoft.com/en-us/library/bb546158.aspx

You can create your own custom QueryProvider as explained in detail here: http://msdn.microsoft.com/en-us/library/bb546158.aspx

琉璃繁缕 2024-12-21 06:58:08

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

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

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

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

I believe you need to compile and then invoke the expression:

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

An alternative might be to pre-compile the expression:

var f = IsSuperhero.Compile();
var loginsBySuperheroes = GetLogins().Where(l => f(l.User));
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文