2014-02-19 1 views
0

Неполадкиcascade = "all" или cascade = "save-update"? NHibernate один-ко-многим не обновит

Когда я создаю экземпляр переходный с коллекцией детей, все становится сохранялись.

Кроме того, если я обновляю экземпляр одного из дочерних объектов, он не обновляется при сохранении родительского объекта.

Я на самом деле с помощью cascade="all"

Problem reproduction

Проблема возникает, когда я загрузил все мои вхождений клиентов, и я изменить счет, хотя я всегда использую тот же ISession.

var repository = new CustomerRepository(session); 
var customers = repository.GetAll(); 
var customer = customers.Where(c => c.Name == "Stack Overflow").FirstOrDefault();   
customer.Invoices 
    .Where(i => i.Number == "1234") 
    .Approve(WindowsIdentity.GetCurrent().Name);  
repository.Save(customer); 

Шаг за шагом отладками ясно показывает repository.Save() метода выполняется, и эти изменения не будут отображаться интой основной базы данных.

Возможно обновление непосредственно к таблице базы данных, поэтому никаких ограничений, приводящих к сбою обновления на стороне базы данных, не возникает.

При этом некоторый код на случай, если он может помочь.

Customer.hbm.xml

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" 
        namespace="MyProject.Model" 
        assembly="MyProject"> 
    <class name="Customer" table="AC_CUST" schema="AC"> 
     <id name="Id" column="AC_CUST_ID" type="Int32" unsaved-value="0"> 
     <generator class="sequence-identity"> 
      <param name="sequence">AC_CUST_ID_SEQ</param> 
      <param name="schema">AC</param> 
     </generator> 
     </id> 
     <property name="Name" column="AC_CUST_NAME" type="String" 
       not-null="true" /> 
     <property name="PhoneNumber" column="AC_CUST_PHNUM" type="Int64" 
       not-null="true" /> 
     <bag name="Invoices" table="ESO_RAPP_ACCES_INFO_DSQ" schema="AC" 
      fetch="join" lazy="true" inverse="true" cascade="all"> 
     <key column="AC_CUST_ID" foreign-key="AC_CUST_INV_FK" /> 
     <one-to-many class="Invoice" /> 
     </bag> 
    </class> 
</hibernate-mapping> 

Customer

public class Customer { 
    public Customer() { Invoices = new List<Invoice>(); } 

    public virtual int Id { get; proected set; } 
    public virtual IList<Invoice> Invoices { get; protected set; } 
    public virtual string Name { get; set; } 
    public virtual string PhoneNumber { get; set; } 
} 

Invoice.hbm.xml

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" 
        namespace="MyProject.Model" 
        assembly="MyProject"> 
    <class name="Invoice" table="AC_INV" schema="AC"> 
     <id name="Id" column="AC_INV_ID" type="Int32" unsaved-value="0"> 
     <generator class="sequence-identity"> 
      <param name="sequence">AC_INV_ID_SEQ</param> 
      <param name="schema">AC</param> 
     </generator> 
     </id> 
     <property name="Approved" column="AC_INV_APPRD" type="DateTime" 
       not-null="false" /> 
     <property name="Approver" column="AC_INV_APPRR" type="String" length="15" 
       not-null="false" /> 
     <property name="Number" column="AC_INV_NUMBR" type="String" length="15" 
       not-null="true" /> 
     <property name="Produced" column="AC_INV_PROD" type="DateTime" 
       not-null="false" /> 
     <many-to-one class="Customer" column="AC_CUST_ID" /> 
    </class> 
</hibernate-mapping> 

Invoice

public class Invoice { 
    public Invoice() { 
     Items = new List<Item>(); 
     Produced = DateTime.Now; 
    } 

    public virtual DateTime? Approved { get; protected set; } 
    public virtual string Approver { get; protected set; } 
    public virtual Customer Customer { get; set; } 
    public virtual int Id { get; proected set; } 
    public virtual string Number { get; set; } 
    public virtual DateTime? Produced { get; set; } 

    public virtual void Approve(string approver) { 
     Approved = DateTime.Now; 
     Approver = approver; 
    } 

    public virtual void Reject() { Produced = null; } 
} 

CustomerRepository

public class CustomerRepository { 
    public CustomerRepository(ISession session) { Session = session; } 

    public ISession Session { get; protected set; } 

    public Customer Save(Customer instance) { 
     Session.SaveOrUpdate(instance); 
     return Instance; 
    } 
} 

Статьи по теме

Любая помощь приветствуется.

+0

В чем ваш 'FlushMode' установлен, когда вы создаете' SessionFactory'? – Rippo

+0

'ISession.FlushMode == FlushMode.Auto'. –

ответ

0

Не забудьте сделать Flush() вашей сессии!

NHibernate отслеживает все изменения в течение жизненного цикла сеанса, которые должны жить только для формы (рабочего стола) или страницы (сети).

Из-за того, что сессия знает обо всех изменениях, она не обязательно фиксирует изменения в базовой базе данных. Вместо этого он записывает все изменения в словарь, а затем, когда он покраснел, вызывая ISession.Flush(), вы действительно требуете, чтобы сессия зафиксировала изменения навсегда.

Так решение должно быть:

repository.Save(customer); 
session.Flush(); 

Или вы можете также кодировать Commit() метод в вашем хранилище, которое будет Flush() сеанс по вызову.

repository.Save(customer); 
repository.Commit(); 

И ваше хранилище будет выглядеть так:

// Assuming you stock your session in the `Session` property. 
public void Commit() { Session.Flush(); } 

Вот и все!