DDD 倉儲目的:隱藏持久化技術細節,保持領域模型純粹。需解決:事務邊界、倉儲實例獲取、多持久化技術可替換。
interface IRepositoryTransactionContext : IDisposable {
IRepository<TEntity> GetRepository<TEntity>() where TEntity : EntityObject, IAggregateRoot;
void BeginTransaction();
void Commit();
void Rollback();
}
倉儲由 Context 產出,自動知悉所屬事務。
internal class EdmRepositoryTransactionContext : IRepositoryTransactionContext {
ObjectContext _objContext;
Dictionary<Type, object> _repoCache = new Dictionary<Type, object>();
public EdmRepositoryTransactionContext(ObjectContext ctx) { _objContext = ctx; }
public IRepository<TEntity> GetRepository<TEntity>() where TEntity : EntityObject, IAggregateRoot {
if (_repoCache.TryGetValue(typeof(TEntity), out var repo)) return (IRepository<TEntity>)repo;
var newRepo = new EdmRepository<TEntity>(_objContext);
_repoCache[typeof(TEntity)] = newRepo;
return newRepo;
}
public void BeginTransaction() { /* EF 由 ObjectContext 管理,無需顯式開始 */ }
public void Commit() => _objContext.SaveChanges();
public void Rollback() { /* EF 自動回滾,Dispose 時處理 */ }
public void Dispose() { _repoCache.Clear(); _objContext.Dispose(); }
}
internal class NHibernateRepositoryTransactionContext : IRepositoryTransactionContext {
ITransaction _tx;
Dictionary<Type, object> _repoCache = new Dictionary<Type, object>();
public ISession Session => DatabaseSessionFactory.Instance.Session;
public IRepository<TEntity> GetRepository<TEntity>() where TEntity : EntityObject, IAggregateRoot {
if (_repoCache.TryGetValue(typeof(TEntity), out var repo)) return (IRepository<TEntity>)repo;
var newRepo = new NHibernateRepository<TEntity>(Session);
_repoCache[typeof(TEntity)] = newRepo;
return newRepo;
}
public void BeginTransaction() => _tx = Session.BeginTransaction();
public void Commit() => _tx.Commit();
public void Rollback() => _tx.Rollback();
public void Dispose() { _tx.Dispose(); if (Session.IsOpen) Session.Close(); }
}
搭配單例 DatabaseSessionFactory 管理 NHibernate Session。
配置檔注入 ObjectContext、EdmRepository、EdmRepositoryTransactionContext。測試代碼:
using (var tx = container.Resolve<IRepositoryTransactionContext>()) {
tx.BeginTransaction();
try {
var cust = Customer.CreateCustomer(...);
tx.GetRepository<Customer>().Add(cust);
tx.Commit();
} catch { tx.Rollback(); throw; }
}
測試通過,資料正確持久化。
NHibernate 需屬性為 virtual 以支援延遲載入 Proxy。修改 EF T4 模板 WritePrimitiveTypeProperty、WriteComplexTypeProperty,在屬性宣告處加入 virtual 關鍵字,避免直接修改生成代碼。
倉儲實作完全解耦技術細節,領域模型純粹度由 DI 保障。事務上下文統一協調多倉儲,支援 EF/NHibernate 熱插拔。下一步:領域事件進一步解耦。