简体   繁体   English

NHibernate一对多无法插入null键

[英]NHibernate one-to-many could not insert null key

I'm trying to use NHibernate. 我正在尝试使用NHibernate。 I have these following tables: 我有以下表格:

    CREATE TABLE person(person_id INTEGER IDENTITY(1,1) NOT NULL,  
    person_first_name VARCHAR(55) NOT NULL,  
    person_last_name VARCHAR(55) NULL,   
    person_contacted_number INTEGER NOT NULL, 
    person_date_last_contacted DATETIME NOT NULL,
    person_date_added DATETIME NOT NULL,  
    CONSTRAINT PK_person PRIMARY KEY (person_id));

    CREATE TABLE person_order(order_id INTEGER IDENTITY(1,1) NOT NULL,  
    order_person_id INT NOT NULL,  
    CONSTRAINT PK_person PRIMARY KEY (order_id)),
    CONSTRAINT FK_person_order_person FOREIGN KEY(order_person_id)
    REFERENCES person (person_id);

Classes: 类别:

    public class Person
    {
        public virtual int person_id { get; set; }
        public virtual String person_first_name { get; set; }
        public virtual String person_last_name { get; set; }
        public virtual int person_contacted_number { get; set; }
        public virtual DateTime person_date_last_contacted { get; set; }
        public virtual DateTime person_date_added { get; set; }
        public virtual ISet<PersonOrder> person_orders { get; set; }
    }
    public class PersonOrder
    {
        public virtual int order_id { get; set; }
        public virtual int order_person_id { get; set; }
        public virtual Person Person { get; set; }
    }

hbm.xml: 的hbm.xml:

  <class name="Person" table="`person`">
        <id name="person_id">
          <generator class="native"/>
        </id>
        <property name="person_first_name" />
        <property name="person_last_name" />
        <property name="person_contacted_number" />
        <property name="person_date_last_contacted" />
        <property name="person_date_added" type="LocalDateTime" />
        <set name="person_orders" table="`person_order`" cascade="all-delete-orphan" inverse="true">
          <key column="order_person_id"/>
          <one-to-many class="PersonOrder"/>
        </set>
  </class>

  <class name="PersonOrder" table="`person_order`">
     <id name="order_id">
      <generator class="native"/>
    </id>
    <many-to-one name="Person" column="order_person_id" cascade="save-update" />
  </class>

I want to save Person to database (cascade): 我想将Person保存到数据库(cascade):

var newPerson = CreatePerson(); // return new Person
newPerson.person_orders = new HashedSet<PersonOrder> {new PersonOrder()};
session.Save(newPerson);

And have a error could not insert: 并且有一个错误无法插入:

[TestConsoleApplication.PersonOrder][SQL: INSERT INTO [person_order] (order_person_id) VALUES (?); select SCOPE_IDENTITY()]

I think it's not correct one-to-many mapping for class. 我认为这对于班级的一对多映射并不正确。 How to resolve this? 怎么解决这个?

I would say, that the most suspected issue could be missing parent/Person setting on the Order itself. 我想说,最可疑的问题可能是订单本身缺少父/人设置。

Once we are not using cascading, NHibernate must know all the settings, independently. 一旦我们不使用级联,NHibernate必须独立地知道所有设置。 Other words, this is not enough *(simplified example, expecting IList instead of IEnumerable for person_orders)*: 换句话说,这还不够*(简化示例,期望IList而不是person_orders的IEnumerable)*:

var newPerson = CreatePerson(); // return new Person
newPerson.person_orders = new List<PersonOrder>();
// WRONG assignment
newPerson.person_orders.Add(new PersonOrder()); // first order
newPerson.person_orders.Add(new PersonOrder()); // second order

In this case, our new PersonOrder does not know about the Person , the reference. 在这种情况下,我们的new PersonOrder不知道Person ,引用。 So we have to be sure, that it is assigned both ways (good practice anyhow): 所以我们必须确保它被分配两种方式(无论如何都是好的做法):

// improve it
var order1 = new PersonOrder
{
    Person = newPerson,
};
var order2 = new PersonOrder
{
    Person = newPerson,
};
newPerson.person_orders.Add(order1); // first order
newPerson.person_orders.Add(order2); // second order

Once this is assured, then after session.Save(newPerson) and session save all orders ... the correct PersonId will be sent. 一旦确定了这一点,那么在session.Save(newPerson)和session之后保存所有订单......将发送正确的PersonId。

NOTE: Try to think about using the cascades, and marking the <set> with inverse="true" attribute. 注意:尝试考虑使用级联,并使用inverse="true"属性标记<set> Honestly cannot remember scenario where not used this approach 老实说不记得没用过这种方法的场景

EDIT: a bit different mapping I would suggest to change the mapping types. 编辑:我建议改变映射类型有点不同的映射。 Instead of iesi ISet (which is really good if we need uniqueness) and the <set> , into standard IList<> and the bag mapping. 而不是iesi ISet (如果我们需要唯一性真的很好)<set> ,而不是标准的IList<>和包映射。 Ie: 即:

Hbm like this : Hbm是这样的:

<bag name="person_orders" table="`person_order`" 
     cascade="all-delete-orphan" inverse="true">
      <key column="order_person_id"/>
      <one-to-many class="PersonOrder"/>
</bag>

the C# like this 像这样的C#

public virtual IList person_orders { get; 公共虚拟IList person_orders {get; set; 组; } }

And the insertion code like this: 插入代码如下:

var newPerson = CreatePerson(); // return new Person
var order = new PersonOrder
{
    Person = newPerson,
};
newPerson.person_orders = new List<PersonOrder> {order};
session.Save(newPerson);

This will work (I am almost sure, because I just reproduced as similar as possible) 这将有效(我几乎可以肯定,因为我只是尽可能地复制)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM