NHibernate:有时我想要一件物品,有时候我想要它们

时间:2009-09-11 14:04:33

标签: nhibernate

我有一个数据库模式,存储一个带有许多“修订版”的“页面”。就像一个简单的维基。

我加载页面时有90%的时间,我只对最新版本感兴趣。但是,有时候我想要所有的修改。

使用NHibernate,我可以将Page映射到Revisions,并告诉它延迟加载。但是,当我访问最新版本时,它将加载所有其他修订 - 大大浪费I / O.

我的网页课目前类似于:

public class Page
{
    public Page()
    {
        Revisions = new HashedSet<Revision>();
    }

    public virtual ISet<Revision> Revisions { get; private set; }

    public virtual Revision LatestRevision
    {
        get { return Revisions.OrderByDescending(x => x.Revised).FirstOrDefault(); }
    }

    public virtual Revision Revise()
    {
        var revision = new Revision();
        // ...
        revision.Entry = this;
        revision.Revised = DateTime.UtcNow;
        Revisions.Add(revision);
        return revision;
    }
}

我如何对此进行建模,以便在加载页面时自动加载LatestRevision,但是,例如,如果我尝试迭代它们,则其他修订是延迟加载的?

我特别喜欢使用LINQ to NHibernate的解决方案,但是使用ICriteria(如果必须的话,甚至是SQL)也足够了。

5 个答案:

答案 0 :(得分:0)

我也在处理类似的问题。

如何完全按照您的方式进行映射。 LatestRevision属性可以映射为修订表的一对一映射,修改将是您已经获得的。您必须拥有一个setter(可能使其成为私有)并在修订方法中管理关系。

一个问题是LatestRevision仍将处于修订集中。

我还看到了Ayende的帖子,该帖子使用了属性的公式属性,我从来没有使用它,但看起来它可能符合要求。

答案 1 :(得分:0)

您可以在映射文件中使用派生属性(而不是在属性中执行逻辑)。它可能看起来像这样:

<property name="LatestRevision"
          forumla="select top r.f1, r.f2, r.etc from Revisions order by revised desc"
          type="Revision" />

有关此方法的更多信息,请搜索“nhibernate派生属性”。

https://www.hibernate.org/hib_docs/nhibernate/1.2/reference/en/html_single/

答案 2 :(得分:0)

添加LatestRevision列(维护它)并映射到该列。 它会为你节省很多麻烦。

答案 3 :(得分:0)

我最终选择了解决方案:

Partially Populate Child Collection with NHibernate

我的页面现在有以下属性:

public virtual Revision CurrentRevision 
{ 
    get
    {
        return _revision ?? Revisions.OrderByDescending(x => x.Revised).FirstOrDefault();
    }
    set { _revision = value; }
}

public virtual ISet<Revision> Revisions { get; private set; }

加载代码为:

public Page GetPage(string name)
{
    var entryHash = (Hashtable)_session.CreateCriteria<Page>("page")
        .Add(Restrictions.Eq("page.Name", name))
        .CreateCriteria("Revisions", "rev")
            .AddOrder(Order.Desc("rev.Revised"))
        .SetMaxResults(1)
        .SetResultTransformer(Transformers.AliasToEntityMap)
        .UniqueResult();
    var page = (Page)entryHash["page"];
    page.LatestRevision = (Revision)entryHash["rev"];
    return page;
}

NHProf将此视为现在唯一正在执行的查询,这是完美的:

SELECT   top 1 this_.Id            as Id3_1_,
               this_.Name          as Name3_1_,
               this_.Title         as Title3_1_,
               rev1_.Id            as Id0_0_,
               rev1_.Body          as Body0_0_,
               rev1_.Revised       as Revised0_0_,
               ....
FROM     [Page] this_
         inner join [Revision] rev1_
           on this_.Id = rev1_.PageId
WHERE    this_.Name = 'foo' /* @p0 */
ORDER BY rev1_.Revised desc

答案 4 :(得分:0)

在Page表中有LatestRevision属性和相应列的问题是什么?

public class Page
{
    public Page()
    {
        Revisions = new HashedSet<Revision>();
    }

    public virtual ISet<Revision> Revisions { get; private set; } // lazy="true"

    public virtual Revision LatestRevision { get; private set; } // lazy="false"

    public virtual Revision Revise()
    {
        var revision = new Revision();
        // ...
        revision.Entry = this;
        revision.Revised = DateTime.UtcNow;
        Revisions.Add(revision);
        LatestRevision = revision; // <- there you have latest revision
        return revision;
    }
}