Reputation: 57
I'm trying to use 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:
<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):
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?
Upvotes: 3
Views: 2049
Reputation: 123861
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. Other words, this is not enough *(simplified example, expecting IList instead of IEnumerable for person_orders)*:
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. 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.
NOTE: Try to think about using the cascades, and marking the <set>
with inverse="true"
attribute. 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. I.e.:
Hbm like this :
<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
public virtual 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)
Upvotes: 1