Я прочитал об атрибутах сопоставления inverse
и cascade
и хотел бы знать:
- Возможно ли их использование в моем сценарии? И если да,
- Как их соответствующим образом параметризовать?
Допустим, у меня есть два класса, Customer
и Invoice
, оба нуждаются в отслеживаемости, TraceableEntity
.
Я использую шаблон репозитория для всех своих сущностей, поэтому репозитории вводятся в конструктор NHibernate.ISession
. Действительно, у меня есть репозиторий для каждой сущности Customer
и Invoice
.
Поскольку мне нужен логин пользователя, я думаю, что это не касается бизнес-модели, поэтому я установил его в методе сохранения репозитория, поскольку только ISession знает о пользователе, используемом для подключения к базовой базе данных, и репозиторий зависит от него. Таким образом, бизнес-модель не загрязняется бесполезной информацией.
Кроме того, из-за этой потребности в отслеживаемости я теряю силу и простоту атрибутов сопоставления inverse
и cascade
, иначе я не знаю, как использовать их для своих конкретных нужд.
Давайте рассмотрим метод
BaseRepository.Save()
.
public abstract class BaseRepository<T> where T : TraceableEntity {
public BaseRepository(ISession session) { Session = session; }
public ISession Session { get; private set; }
public T Save(T instance) {
if (instance.IsNew && instance.IsDirty)
instance.Creator = readLoginFromConnectionString();
else if (!instance.IsNew && (instance.IsDirty || instance.IsDeleted))
instance.Updater = readLoginFromConnectionString();
Session.SaveOrUpdate(instance);
return instance;
}
}
TraceableEntity
public abstract class TraceableEntity {
public TraceableEntity() {
Created = DateTime.Today;
IsNew = true;
}
public virtual DateTime Created { get; set; }
public virtual string Creator { get; set; }
public virtual DateTime? Deleted { get; set; }
public virtual int Id { get; protected set; }
public virtual bool IsDeleted { get; set; }
public virtual bool IsDirty { get; set; }
public virtual bool IsNew { get; set; }
public virtual DateTime? Updated { get; set; }
public virtual string Updater { get; set; }
}
Customer
public class Customer : TraceableEntity {
public Customer() : base() { Invoices = new List<Invoice>(); }
public virtual Name { get; set; }
public virtual Number { get; set; }
public virtual IList<Invoice> Invoices { get; private set; }
}
Customer.hbm.xml
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="MyProject.Model"
assembly="MyProject">
<class name="Customer" table="CUSTOMERS">
<id name="Id" column="CUST_ID" type="Int32" unsaved-value="0">
<generator class="sequence-identity">
<param name="sequence">CUST_ID_SEQ</param>
</generator>
</id>
<property name="Name" column="CUST_NAME" type="String" length="128" not-null="true" />
<property name="Number" column="CUST_NUMBER" type="String" length="12" not-null="true" />
<property name="Creator" column="CUST_CREATOR_USR_ID" type="String" length="15" not-null="true" />
<property name="Created" column="CUST_CREATED_DT" type="DateTime" not-null="true" />
<property name="Updater" column="CUST_UPDATER_USR_ID" type="String" length="15" />
<property name="Updated" column="CUST_UPDATED_DT" type="DateTime" not-null="false" />
<property name="Deleted" column="CUST_DELETED_DT" type="DateTime" not-null="false" />
<bag name="Invoices" table="INVOICES" fetch="join" lazy="true" inverse="true">
<key column="CUST_ID" foreign-key="INV_CUST_ID_FK" />
<one-to-many class="Invoice" />
</bag>
</class>
</hibernate-mapping>
Invoice
public class Invoice : TraceableEntity {
public Invoice() : base() { }
public virtual Customer Customer { get; set; }
public virtual DateTime InvoiceDate { get; set; }
public virtual string Number { get; set; }
public virtual float Total { get; set; }
}
Invoice.hbm.xml
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="MyProject.Model"
assembly="MyProject">
<class name="Invoice" table="INVOICES">
<id name="Id" column="INV_ID" type="Int32" unsaved-value="0">
<generator class="sequence-identity">
<param name="sequence">INV_ID_SEQ</param>
</generator>
</id>
<property name="InvoiceDate" column="INV_DT" type="DateTime" not-null="true" />
<property name="Number" column="INV_NUMBER" type="String" length="12" not-null="true" />
<property name="Total" column="INV_TOTAL" type="decimal" not-null="true" />
<property name="Creator" column="INV_CREATOR_USR_ID" type="String" length="15" not-null="true" />
<property name="Created" column="INV_CREATED_DT" type="DateTime" not-null="true" />
<property name="Updater" column="INV_UPDATER_USR_ID" type="String" length="15" />
<property name="Updated" column="INV_UPDATED_DT" type="DateTime" not-null="false" />
<property name="Deleted" column="INV_DELETED_DT" type="DateTime" not-null="false" />
<many-to-one name="Customer" class="Customer" column="CUST_ID" />
</class>
</hibernate-mapping>
При этом я хотел бы знать, есть ли другой, возможно, лучший способ сделать это, потому что на самом деле мне нужно в CustomerRepository
переопределить метод BaseRepository.Save()
только для вызова метода InvoiceRepository.Save()
следующим образом:
public class CustomerRepository : BaseRepository<Customer> {
public CustomerRepository(ISession session) : base(session) { }
public override Customer Save(Customer instance) {
instance = base.Save(instance);
var invoices = new InvoiceRepository(session);
instance.Invoices.ToList().ForEach(inv => {
inv.Customer = instance;
invoices.Save(inv)
});
}
}
public class InvoiceRepository : BaseRepository<Invoice> {
public InvoiceRepository(ISession session) : base(session) { }
}
Кроме того, мне интересно, возможно ли, чтобы счета «знали», кто является клиентом, без необходимости назначать свойство «Клиент» при сохранении, и пусть магия NHibernate работает для меня?