NHibernate:如何在一对一映射上启用延迟加载

时间:2008-12-23 14:42:25

标签: nhibernate nhibernate-mapping

nhibernate中的一对一关系可以延迟加载“false”或“proxy”。我想知道是否有人知道如何做一个懒惰的一对一映射。

我通过使用映射到私有字段的惰性集来实现相同的结果,并让公共属性返回该集的第一个结果。它有效,但不是最干净的代码......

提前致谢!

6 个答案:

答案 0 :(得分:20)

除非必须关联,否则不支持延迟加载一对一。有关推理,请参阅here

归结为这样一个事实:为了确定关系的另一面是否存在(N)Hibernate必须转到数据库。由于您已经使用了数据库命中,因此您也可以加载完整的对象。

虽然有些情况下只是为了查看相关对象是否存在而没有实际加载对象是有意义的(如果相关对象非常“重”),但NHibernate目前不支持它。

答案 1 :(得分:4)

据我所知,懒惰加载一对一并不是一种非黑客的方法。我希望我错了,但上次我查了一下就是这样。

答案 2 :(得分:4)

有想法。它详细描述了here

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernateTest" namespace="NHibernateTest">
  <class name="Person" >
    <id name="PersonID" type="Int32">
      <generator class="identity" />
    </id>
    <property name="LastName" type="String" length="50" />
    <property name="FirstName" type="String" length="50" />
    <many-to-one name="Photo" class="PersonPhoto" />
  </class>

  <class name="PersonPhoto">
    <id name="PersonID" type="Int32">
      <generator class="foreign">
        <param name="property">Owner</param>
      </generator>
    </id>
    <property name="Photo" type="BinaryBlob" />
    <one-to-one name="Owner" class="Person" constrained="true" />
  </class>
</hibernate-mapping> 

答案 3 :(得分:2)

我尝试了上面Artem Tikhomirov使用的例子。我不断收到Photo列不存在的错误。看了this后,我发现映射有点偏差。当我更改多对一映射以指定列名时,如下所示:

多对一名称=“Photo”column =“PersonID”class =“PersonPhoto”unique =“true”

我得到了它的工作。我希望这有助于某人:o)

答案 4 :(得分:0)

在阅读完此处的答案后,我设法使其正常工作。 我将添加此示例,因为我使用的是 Constrained = False 的一对一关系,并且因为它是“按代码示例映射”

两个类别:

public class Pedido:BaseModel
{
    public virtual BuscaBase Busca { get; set; }
}

public class BuscaBase : BaseModel
    {       
        public virtual Pedido Pedido { get; set; }
    }

映射:

public class PedidoMap : ClassMapping<Pedido>
{
    public PedidoMap()
    {
         Id(x => x.Id, x => x.Generator(Generators.Identity));            

         ManyToOne(x => x.Busca, m => 
         { 
             m.Cascade(Cascade.DeleteOrphans);
             m.NotNullable(true); m.Unique(true);
             m.Class(typeof(BuscaBase));
         });    
    }
}

public class BuscaBaseMap : ClassMapping<BuscaBase>
{
    public BuscaBaseMap()
    {            
        Id(x => x.Id, x => x.Generator(Generators.Sequence, g => g.Params(new { sequence = "buscaefetuada_id_seq" })));

        OneToOne(x => x.Pedido, m =>
        {
            m.Lazy(LazyRelation.NoProxy);
            m.Constrained(false);
            m.Cascade(Cascade.None);
            m.Class(typeof(Pedido));
        });            
    }
}

注意:我正在使用“一对一”映射m.PropertyReference(typeof(Pedido).GetProperty("Busca"));,但这不适用于延迟加载。您必须使用Class来指定关系

关于此处使用的Constrained = False的简要介绍,“ BuscaBase”对象中可能不存在“ Pedido”对象。

答案 5 :(得分:0)

对我有用的是以下内容(与@Daniel 非常相似),但我发现有必要在映射的两端指定 LazyRelation.NoProxy。

  public class Person
    {
        public virtual int Id { get; set; }

        public virtual string Name { get; set; }

        public virtual PersonDetails Details { get; set; }

        public class PersonMap : ClassMapping<Person>
        {
            public PersonMap()
            {
                Id(x => x.Id, m =>
                {
                    m.Generator(Generators.Native);
                });

                 
                Property(x => x.Name);

                OneToOne(x => x.Details, m =>
                { 
                    m.Lazy(LazyRelation.NoProxy);
                    m.Cascade(Cascade.Persist); 
                });
            }
        }
    }

    public class PersonDetails
    {
        public virtual int Id { get; set; }

        public virtual string ExtraDetails { get; set; }

        public virtual Person Person { get; set; }

        public class PersonDetailsMap : ClassMapping<PersonDetails>
        {
            public PersonDetailsMap()
            {

                Id(x => x.Id, m =>
                {
                    m.Generator(Generators.Native);
                }); 

                Property(x => x.ExtraDetails);
                
                ManyToOne(x => x.Person, m =>
                {
                    m.Lazy(LazyRelation.NoProxy);
                    m.Unique(true);
                    m.NotNullable(true); 
                });
            }
        }
    }


using var session = NhHelper.OpenSession();

var person1 = new Person();
person1.Name = "A";

var person1Details = new PersonDetails();
person1Details.ExtraDetails = "A details"; 

person1.Details = person1Details;
person1Details.Person = person1;

session.Save(person1);
//because of PersonMapping's Cascade.Persist it is not necessary to manually save person1Details object.
 

using var session = NhHelper.OpenSession();
foreach(var person in session.Query<Person>()) {
  Console.WriteLine(person.Name);  //<-- does not load PersonDetails unless it's property is accessed
}
  • NHibernate 5.3.5
  • Npgsql 5.0.3 (Postgresql Db)。