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

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

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

1 ответ

Решение

Не забудь 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(); }

Это все!

Другие вопросы по тегам