2010-04-14 104 views
1

我正在學習NHibernate或者學習NHibernate,所以忍耐着我。用NHibernate保存子集合

我有一個Order類和一個Transaction類。訂單與交易有一對多的關係。我的數據庫中的事務表在OrderId外鍵上有一個非空限制。

Order類:

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>(); 
    } 
} 

訂單映射:

<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> 

交易類別:

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; } 
} 

交易映射:

<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"/> 

我真的不想要一個雙向關聯。我的交易對象不需要直接引用它們的訂單對象(我只需要訪問訂單的交易)。但是,我不得不添加這讓Order.Transactions被保存到數據庫:

庫:

 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(); 
      } 
     } 
    } 

我的問題是,這將隨後發出更新的指令集的每一筆交易(不管它是否已經改變)。

我試圖讓周圍的人不必保存訂單之前明確地保存事務,而不是僅僅增加交易的訂單,然後保存訂單:

 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); 
    } 

雖然我已經找到一個相當關於建立一對多協會的文章很少,其中大多數討論檢索數據而不是堅持回來。

非常感謝, 本

回答

2

你需要設置你的映射級聯屬性,以便持久性級聯到子對象:

<set name="Transactions" table="Transactions" lazy="false" inverse="true" cascade="all-delete-orphan"> 

您的訂單對象應該有設置一個AddTransaction方法父母對孩子的引用。例如:

public void AddTransaction(Transaction txn) 
{ 
    txn.Order = this; 
    Transactions.Add(txn); 
} 

這將導致事務對象在持久化訂單時被持久化。您可以使用internal修飾符公開交易上的Order屬性,以便它不公開可見。

+0

@Jamie - 這當然有效,儘管它仍然看起來像是一個更新查詢是爲每個屬於訂單的交易執行的。我想我覺得NH會找出發生了什麼變化,並且只對任何新的事務發出插入,並且對已更改的任何事務進行更新。也許我問得太多了? :) – 2010-04-14 14:25:39

+0

不,這是它應該工作的方式。你可能有一個「鬼」的問題,即一個值意外改變。在Transaction映射中設置'dynamic-update =「true」'並查看正在發佈的SQL(通過分析器或日誌記錄)。您可能會發現您的對象無意中改變了某個值。 – 2010-04-14 14:58:51

+0

@Jamie我已經查看了生成的SQL,並且我沒有更改現有事務的任何值。 我的示例代碼檢索現有訂單,向訂單添加新的交易,然後保存訂單。如果我爲該訂單執行四個現有交易,則執行的總SQL如下所示: 1. select * from order where id = blah 2. select * from transaction where orderId = blah 3.插入交易(新交易) 4。更新訂單(將值設置爲與原始相同) 5.更新交易1,2,3,4(將值設置爲與之前相同) – 2010-04-14 15:19:56