Reputation: 34800
I am in the process or learning NHibernate so bear with me.
I have an Order class and a Transaction class. Order has a one to many association with transaction. The transaction table in my database has a not null constraint on the OrderId foreign key.
Order class:
public class Order {
public virtual Guid Id { get; set; }
public virtual DateTime CreatedOn { get; set; }
public virtual decimal Total { get; set; }
public virtual ICollection<Transaction> Transactions { get; set; }
public Order() {
Transactions = new HashSet<Transaction>();
}
}
Order Mapping:
<class name="Order" table="Orders">
<cache usage="read-write"/>
<id name="Id">
<generator class="guid"/>
</id>
<property name="CreatedOn" type="datetime"/>
<property name="Total" type="decimal"/>
<set name="Transactions" table="Transactions" lazy="false" inverse="true">
<key column="OrderId"/>
<one-to-many class="Transaction"/>
</set>
Transaction Class:
public class Transaction {
public virtual Guid Id { get; set; }
public virtual DateTime ExecutedOn { get; set; }
public virtual bool Success { get; set; }
public virtual Order Order { get; set; }
}
Transaction Mapping:
<class name="Transaction" table="Transactions">
<cache usage="read-write"/>
<id name="Id" column="Id" type="Guid">
<generator class="guid"/>
</id>
<property name="ExecutedOn" type="datetime"/>
<property name="Success" type="bool"/>
<many-to-one name="Order" class="Order" column="OrderId" not-null="true"/>
Really I don't want a bidirectional association. There is no need for my transaction objects to reference their order object directly (I just need to access the transactions of an order). However, I had to add this so that Order.Transactions is persisted to the database:
Repository:
public void Update(Order entity)
{
using (ISession session = NHibernateHelper.OpenSession()) {
using (ITransaction transaction = session.BeginTransaction()) {
session.Update(entity);
foreach (var tx in entity.Transactions) {
tx.Order = entity;
session.SaveOrUpdate(tx);
}
transaction.Commit();
}
}
}
My problem is that this will then issue an update for every transaction on the order collection (regardless of whether it has changed or not).
What I was trying to get around was having to explicitly save the transaction before saving the order and instead just add the transactions to the order and then save the order:
public void Can_add_transaction_to_existing_order()
{
var orderRepo = new OrderRepository();
var order = orderRepo.GetById(new Guid("aa3b5d04-c5c8-4ad9-9b3e-9ce73e488a9f"));
Transaction tx = new Transaction();
tx.ExecutedOn = DateTime.Now;
tx.Success = true;
order.Transactions.Add(tx);
orderRepo.Update(order);
}
Although I have found quite a few articles covering the set up of a one-to-many association, most of these discuss retrieving of data and not persisting back.
Many thanks, Ben
Upvotes: 1
Views: 3650
Reputation: 49261
You need to set the cascade attribute on your mapping so that persistence is cascaded to the child objects:
<set name="Transactions" table="Transactions" lazy="false" inverse="true" cascade="all-delete-orphan">
Your Order object should have an AddTransaction method that sets the parent reference on the child. Something like:
public void AddTransaction(Transaction txn)
{
txn.Order = this;
Transactions.Add(txn);
}
This will cause the Transaction object to be persisted when the Order is persisted. You can expose the Order property on Transaction with the internal
modifier so that it's not publicly visible.
Upvotes: 3