【问题标题】:NHibernate - possible to fetch a collection after querying?NHibernate - 查询后可以获取集合吗?
【发布时间】:2011-08-11 15:54:50
【问题描述】:

在使用 .Fetch 进行实际查询时,关于获取和预加载的文献太多了

但是,一旦我有一个加载的实体 - 带有一个空集合(因为我选择不在查询时急切加载,因为笛卡尔积的副作用),我可以选择稍后加载一个集合,比如说在我完成了一些分页之后,我有了一个具体的项目列表?

类似:

var list = (some linq over Session.Query<Entity>)
.Take(10).Skip(2)
.Fetch(x => x.MyCollection)
.ToList();

Session.Fetch<Entity>(list, l => l.OtherCollection);

编辑 关键是 - 我已经在 Query 中获取 2 个子集合 - 使查询和结果集已经相当大(参见 nhibernate Cartesian product)。我想对结果进行分页,获取 10 个列表,然后可以选择返回数据库以填充分页(例如 10 个)结果的子集合属性。这是性能方面的考虑。

【问题讨论】:

    标签: nhibernate lazy-loading


    【解决方案1】:

    发出这个查询

    /*we dont need the result*/Session.QueryOver<Entity>()
        .Where(x => x.Id.IsIn(list.Select(l => l.Id)))
        .Fetch(l => l.OtherCollection)
        .ToList();
    

    然后 nhibernate 应该初始化实体上的集合

    编辑:

    要改善初始加载时间,请参阅http://ayende.com/blog/4367/eagerly-loading-entity-associations-efficiently-with-nhibernate

    那么你可以做例子

    var results = (some linq over Session.Query<Entity>)
        .Take(10).Skip(2)
        .ToList();
    
    var q = Session.QueryOver<Entity>()
        .Where(x => x.Id.IsIn(list.Select(l => l.Id)))
        .Fetch(l => l.MyCollection)
        .ToFuture();
    
    Session.QueryOver<Entity>()
        .Where(x => x.Id.IsIn(list.Select(l => l.Id)))
        .Fetch(l => l.OtherCollection)
        .ToFuture();
    
    Session.QueryOver<Entity>()
        .Where(x => x.Id.IsIn(list.Select(l => l.Id)))
        .Fetch(l => l.ThirdCollection)
        .ToFuture();
    
    return q.ToList()
    

    【讨论】:

    • 这不就是急切加载吗?我正在谈论在断开连接的实体或断开连接的实体组上获取集合。
    • @BobTodd 不知道您已断开连接的实体。但是用session.Lock(obj, LockMode.None); 重新连接它们然后执行加载应该是微不足道的。 sessioncache 将确保现有实体将被初始化
    • 看起来我们在我的回答中发现了同样的事情(见评论) - 如果原始查询很昂贵并且您只想执行一次怎么办?考虑到实际的 sql 来执行它,它不会很漂亮,因为查询必须看起来像 select * from mycollection where parentid in(id1, id2, id3, id4),但是对于 10 个分页结果,它的性能要好得多一遍又一遍地运行主查询
    • 你能看到我关于我的答案的最新帖子吗?
    【解决方案2】:

    我刚刚开始阅读 NHibernate 中的未来和预测,它们看起来很有希望作为一种解决方案......当我发现它时会发布更多信息。

    这是一个解决方案:http://ayende.com/blog/4367/eagerly-loading-entity-associations-efficiently-with-nhibernate,但我仍然不喜欢它,因为我的查询本身非常昂贵(使用 '%like%@ + 分页),所以执行 3 或 4 次只是为了加载集合似乎很昂贵

    编辑

    这就是我所拥有的。查看生成的 sql,正确的 sql 正在运行并返回预期结果,但返回结果上的集合为空。你能看到缺少什么吗?:

    public List<Company> CompaniesForLoggedInUser(int pageSize, int pageNumber)
        {
          var list =
            QueryForCompaniesFor(SecurityHelper.LoggedInUsername)
              .Page(pageNumber, pageSize)
              .ToList()
              .FetchCompanyCollections(Session);
          return list;
        }
    
    internal static class CompanyListExtensions
      {
        internal static List<Company> FetchCompanyCollections(this List<Company> companies, ISession session)
        {
          var ids = companies.Select(l => l.Id).ToArray();
    
          session.QueryOver<Company>()
            .Where(x => x.Id.IsIn(ids))
            .Fetch(l => l.Properties).Eager()
            .Future();
    
          return session.QueryOver<Company>()
            .Where(x => x.Id.IsIn(ids))
            .Fetch(l => l.UserAccessList).Eager()
            .Future()
            .ToList();
        }
      }
    

    【讨论】:

    • 对我来说看起来不错,但你能试试session.QueryOver&lt;Company&gt;() .Where(x =&gt; x.Id.IsIn(ids)) .Fetch(l =&gt; l.UserAccessList).Eager() .Future() .ToList(); return companies;
    • 我的问题是 ToListing 第二个未来而不是第一个,您的原始答案是正确的(但缺少 ToList)
    猜你喜欢
    • 1970-01-01
    • 2017-12-26
    • 1970-01-01
    • 1970-01-01
    • 2021-09-18
    • 1970-01-01
    • 2010-12-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多