【问题标题】:Where-clause for LINQ-to-NHibernate FetchMany?LINQ-to-NHibernate FetchMany 的 Where 子句?
【发布时间】:2013-07-11 23:20:44
【问题描述】:

使用 LINQ-to-NHibernate 有没有办法缩小 FetchMany() 返回的范围?

给定以下类结构

public class Foo
{
  public virtual int Id { get; set; }
  public virtual IList<Bar> Bars { get; set; }
}
public class Bar
{
  public virtual string Description { get; set; }
}

我该怎么做:

session.Query<Foo>()
  .Where(foo => foo.Id > 30)
  .FetchMany(foo => 
    foo.Bars.Where(bar => bar.Description.StartsWith("x")));

NHibernate 将返回所有 Id > 30 的 Foo 以及对于那些 Foo 的所有附加 Bar,其中 Bar 的描述以字母 'x' 开头?

我发现一些帖子使用旧的 QueryOver() 东西,但我明确地想使用 NHibernate 的 LINQ 提供程序。

有什么想法吗?


更新

我认为我需要澄清我想要的结果。

<Foo Id="1">
  <Bar Description="x1"/>
  <Bar Description="b1"/>
</Foo>
<Foo Id="31">
  <Bar Description="x2"/>
  <Bar Description="x3"/>
  <Bar Description="b2"/>
</Foo>
<Foo Id="32">
  <Bar Description="b3"/>
</Foo>

根据上述数据,我预计会有以下结果

<Foo Id="31">
  <Bar Description="x2"/>
  <Bar Description="x3"/>
</Foo>
<Foo Id="32"/>

附加的 Where 子句应该只对 Bar 有效!它不应该进一步缩小 Foo 的列表!只需减少 FetchMany() 返回的内容即可。

【问题讨论】:

  • 现在返回什么?
  • @GertArnold 现在该查询甚至无法编译...如果我删除第二个 Where 子句,它将返回所有 Id > 30 的 Foo 以及每个附加到它们的所有条。我找不到对“FetchMany()”调用将返回的内容进行任何过滤的方法。
  • @SebastianWeber 你找到解决方案了吗?
  • @SarabjeetSingh 对不起,我真的不记得了。 DanP 提到的过滤器的想法听起来有点熟悉,但我不确定我们是否真的使用了那个。
  • @SarabjeetSingh 刚刚偶然发现了release notes for EFCore 5.0,他们在其中添加了对该功能的支持

标签: linq nhibernate linq-to-nhibernate


【解决方案1】:

我很确定您对当前的 linq 提供程序不走运 - 但​​对于非 linq(和横切)选项,您可能想看看 NHibernate 中包含的 filter 功能- 这可能是在大型/复杂项目中实施此功能的最佳选择。

【讨论】:

    【解决方案2】:
    var query = from foo in session.Query<Foo>()
                where foo.Id >30
                from bar in foo.Bars
                where bar.Description.StartsWith("x")
                select new { Id = foo, Bar = bar};
    var results = query.ToList().ToLookup(x => x, x => x.Bar);
    foreach(var foo in results.Keys)
    {
       var barsWhichStartWithX = results[foo];
       //DO STUFF
    }
    

    虽然这可能会产生低效的 SQL(我不使用 nHibernate,所以我不知道)。你也可以试试这个……而且上面会错过没有酒吧的 foos。

    var foosQuery = session.Query<Foo>().Where(foo => foo.Id > 30);
    var foos = foosQuery.Future();
    var barsQuery = from f in foosQuery
                    from bar in foo.Bars
                    select new { Id = foo.Id, Bar = bar};
    var foosDict = foos.ToDictionary(x => x.Id);
    var bars = barsQuery.ToList().ToLookup(x => foosDict[x.Id], x => x.Bar);
    foreach(var foo in foos)
    {
       var barsWhichStartWithX = bars[foo];
       //DO STUFF
    }
    

    【讨论】:

      【解决方案3】:

      也许不是完全你所追求的,但肯定值得考虑的是NHibernate.CollectionQuery 库。

      它允许您使用 Linq 在实体上查询未初始化的 NHibernate 集合 - 但需要额外的查询/往返才能获取它们(与 FetchMany 不同,后者在同一往返中获取整个集合)。

      【讨论】:

      • 会产生SELECT N+1问题。
      • 我们有一个相当复杂的对象层次结构。手动查询每个集合会增加太多开销(无论是代码还是往返次数)。但它看起来是一个有趣的项目。
      【解决方案4】:

      您需要从子对象到父对象的引用。

      var result = from foo in session.Query<Foo>().FetchMany(f => f.Bars)
                   from bar in session.Query<Bar>()
                   where foo.Id == bar.FooId && // FooId is missing in your entity
                         foo.Id > 30
                         bar.Description.StartsWith("x")
                   select foo;
      

      【讨论】:

      • 在我们的模型中没有从 Bar 到 Foo 的“反向链接”,我们不打算仅仅为了这些查询而引入一个。
      猜你喜欢
      • 2023-03-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-28
      • 2015-08-29
      相关资源
      最近更新 更多