NHibernate - 一对一级联设置

时间:2011-01-22 11:05:44

标签: nhibernate nhibernate-mapping

我在Person类和Employee之间有一对一的关系。我希望INSERT从Person级联到Employee。但是,这不会发生。我在一对一关系元素上尝试过cascade ='all'和cascade ='save-update',但它没有用。

我的对象的结构如下:

public class Person
{
    public virtual Employee Employee { get; set; }
    public virtual int Age { get; set; }
    public virtual string Forename { get; set; }
    public virtual string Surname { get; set; }
    public virtual int PersonID { get; set; }
}

public class Employee
{
    public virtual int PersonID { get; set; }
    public virtual string PayRollNo { get; set; }
    public virtual int Holidays { get; set; }
    public virtual Person Person { get; set; }
}

映射文件如下所示:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="Employee, Employee.DAL" table="`Employee`"  >
    <id name="PersonID" column="`PersonId`" type="int">
      <generator class="native" />
    </id>
    <property type="string" length="30" name="PayRollNo" column="`PayRollNo`" />
    <property type="int" name="Holidays" column="`Holidays`" />
    <one-to-one name="Person"  class="Person" cascade="all"/>
  </class>
</hibernate-mapping>

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="Person, Employee.DAL" table="`Person`"  >    
    <id name="PersonID" column="`PersonId`">
      <generator class="foreign">
        <param name="property" >Employee</param>
      </generator>
    </id>
    <property type="string" name="Forename" column="`Forename`" />
    <property type="string" name="Surname" column="`Surname`" />
    <property type="int" name="Age" column="`Age`" />
    <one-to-one name="Employee" class="Employee"  constrained="true"  />
  </class>
</hibernate-mapping>

启动对象并保存对象的代码:

var employee = new Employee();

    employee.Person = new Person { Employee = employee };

    ISessionFactory sessionFactory = (new Configuration()).Configure().BuildSessionFactory();

    employee.Person.Age = 27;
    employee.Person.Forename = "N";
    employee.Person.Surname = "M";

    employee.PayRollNo = "12";
    employee.Holidays = 27;

    using (var session = sessionFactory.OpenSession())
    {
        session.Save(employee);        
    }

3 个答案:

答案 0 :(得分:2)

Yads基本上是正确的。第二个<one-to-one>(从员工到人员)需要constrained="true"。这样,以下代码应该可以工作:

using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{
    var person = new PersonDataContext();
    person.Employee = new EmployeeDataContext { Person = person };
    session.Save(person);
    tx.Commit();
}

另外一些建议:

  • 使用lazy="false"。阅读http://ayende.com/Blog/archive/2010/08/04/nhibernate-is-lazy-just-live-with-it.aspx
  • 为您的班级使用更多DDD名称。您有一个表示Person的实体,其数据存储在Person表中。你为什么称它为 PersonDataContext
  • 您要映射到属性,而不是字段。在类中显示属性的代码而不是基础字段。
  • 您无需使用默认值覆盖。如果属性的名称为PayRollNo,则默认列名为PayRollNo。如果属性的类型为int,则默认的映射类型也为int

答案 1 :(得分:0)

根据此http://nhibernate.info/doc/nh/en/index.html#mapping-declaration-onetoone您错过了人物映射中constrained="true"元素中的<one-to-one>

答案 2 :(得分:0)

将session.Save()方法放在事务中。或者在调用save方法之后使用session.Flush()方法。

       using (var trans = session.BeginTransaction())
            {
                try
                {
                    trans.Begin();
                    session.Save(employee);
                    trans.Commit();
                }
                catch
                {
                    trans.Rollback();
                    throw;
                }
            }

Nhibernate偶尔会存储SQL语句以同步内存中的日期。 session.Flush()方法将SQL提交到数据库。这在transcation.Commit()方法上默认发生。

有关更多信息,请参阅Nhibernate文档http://nhibernate.info/doc/nh/en/index.html#manipulatingdata-flushing