如何使用存儲庫模式以事務方式封裝保存多個實體?例如,如果我想添加訂單並根據訂單創建更新客戶狀態,但只有在訂單成功完成時纔會這樣做。請記住,在本例中,訂單不是客戶內部的集合。他們是他們自己的實體。存儲庫模式中的事務
這只是一個人爲的例子,所以我並不關心訂單是否應該在客戶對象內部,或者甚至在相同的有界環境中。我並不在乎底層技術的用途(nHibernate,EF,ADO.Net,Linq等)。我只是想看看在這個公認的人爲操作的例子中,一些調用代碼可能看起來像什麼樣子。
如何使用存儲庫模式以事務方式封裝保存多個實體?例如,如果我想添加訂單並根據訂單創建更新客戶狀態,但只有在訂單成功完成時纔會這樣做。請記住,在本例中,訂單不是客戶內部的集合。他們是他們自己的實體。存儲庫模式中的事務
這只是一個人爲的例子,所以我並不關心訂單是否應該在客戶對象內部,或者甚至在相同的有界環境中。我並不在乎底層技術的用途(nHibernate,EF,ADO.Net,Linq等)。我只是想看看在這個公認的人爲操作的例子中,一些調用代碼可能看起來像什麼樣子。
我會看看使用某種類型的事務範圍/上下文系統。所以你可能有下面的代碼,它大致基於.Net & C#。
public class OrderService
{
public void CreateNewOrder(Order order, Customer customer)
{
//Set up our transactional boundary.
using (TransactionScope ts=new TransactionScope())
{
IOrderRepository orderRepos=GetOrderRespository();
orderRepos.SaveNew(order);
customer.Status=CustomerStatus.OrderPlaced;
ICustomerRepository customerRepository=GetCustomerRepository();
customerRepository.Save(customer)
ts.Commit();
}
}
}
TransactionScope可以嵌套,所以假設你有一個跨越多個服務的動作,你的應用程序也會創建一個TransactionScope。如果您使用TransactionScope,那麼現在在.net中,您有可能會對DTC產生影響,但將來會解決這個問題。
我們創建了自己的TransactionScope類,它基本上管理了我們的數據庫連接並使用了本地SQL事務。
你想看看實施工作模式的單位。有NHibernate的實現。一個在Rhino Commons項目中,還有Machine.UoW。
使用Spring.NET AOP + NHibernate的,你可以寫你的倉庫類爲正常和自定義XML文件來配置你的交易:
public class CustomerService : ICustomerService
{
private readonly ICustomerRepository _customerRepository;
private readonly IOrderRepository _orderRepository;
public CustomerService(
ICustomerRepository customerRepository,
IOrderRepository orderRepository)
{
_customerRepository = customerRepository;
_orderRepository = orderRepository;
}
public int CreateOrder(Order o, Customer c)
{
// Do something with _customerRepository and _orderRepository
}
}
在您選擇您想在內部執行該方法的XML文件交易:
<object id="TxProxyConfigurationTemplate"
abstract="true"
type="Spring.Transaction.Interceptor.TransactionProxyFactoryObject, Spring.Data">
<property name="PlatformTransactionManager" ref="HibernateTransactionManager"/>
<property name="TransactionAttributes">
<name-values>
<add key="Create*" value="PROPAGATION_REQUIRED"/>
</name-values>
</property>
</object>
<object id="customerService" parent="TxProxyConfigurationTemplate">
<property name="Target">
<object type="MyNamespace.CustomerService, HibernateTest">
<constructor-arg name="customerRepository" ref="customerRepository" />
<constructor-arg name="orderRepository" ref="orderRepository" />
</object>
</property>
</object>
並在代碼中,你得到的CustomerService類的一個實例是這樣的:
ICustomerService customerService = (ICustomerService)ContextRegistry
.GetContent()
.GetObject("customerService");
Spring.NET將返回一個CustomerService類的代理,該類將在您調用CreateOrder方法時應用事務。這樣,您的服務類中就沒有特定於交易的代碼。 AOP照顧它。欲瞭解更多詳情,你可以看看Spring.NET的文檔。
如何封裝的 節約超過一個實體更多使用 庫模式的 事務的方式?例如,如果我想添加訂單並根據 訂單創建客戶狀態 更新什麼 ,但只有在訂單成功完成 訂單時才這樣做?保留在 請注意,對於此示例,訂單 不是客戶內部的集合。 他們是他們自己的實體。
它不是倉庫的責任,它通常是在更高層次上完成的。雖然你說你對特定技術不感興趣,但我認爲它值得追求解決方案,例如在使用NHibernate和Web應用程序時,你可能會考慮使用session-per request。
所以,如果你能夠在更高層次上的管理事務,然後我的兩個選擇是:
如果您選擇第二個選項,那麼問題是內存中的對象會發生什麼,您的客戶可能會處於不一致的狀態。如果這一點很重要,而且我的工作方式並不像對象只是爲了請求而加載的那樣,那麼我會考慮先檢查它是否可能,因爲它比替代方案更容易(回滾內 - 內存更改或重新加載對象)。
爲什麼它不是倉庫的責任?將數據庫操作從領域模型中抽象出來不是整個想法嗎?對我而言,存儲庫是放置該事務支持的最佳地點。 – 2009-02-22 19:31:27
今天早上啓動我的電腦我遇到了我正在進行的項目的確切問題。我有一些想法導致了以下設計 - 評論將不僅僅是真棒。不幸的是,Josh建議的設計是不可能的,因爲我必須使用遠程SQL服務器,並且無法啓用它所依賴的Distribute Transaction Coordinator服務。
我的解決方案基於對現有代碼的一些簡單更改。
首先,我有我的所有存儲庫實現一個簡單的標記接口:
/// <summary>
/// A base interface for all repositories to implement.
/// </summary>
public interface IRepository
{ }
其次,我讓我所有的交易使倉庫實現以下接口:
/// <summary>
/// Provides methods to enable transaction support.
/// </summary>
public interface IHasTransactions : IRepository
{
/// <summary>
/// Initiates a transaction scope.
/// </summary>
void BeginTransaction();
/// <summary>
/// Executes the transaction.
/// </summary>
void CommitTransaction();
}
的想法是,在我所有的存儲庫都實現了這個接口,並添加了直接引入事務的代碼,具體取決於實際的提供者(對於僞代碼庫,我已經創建了一個在提交時執行的代理列表)。對於LINQ to SQL中它會很容易做出的實現,例如:
#region IHasTransactions Members
public void BeginTransaction()
{
_db.Transaction = _db.Connection.BeginTransaction();
}
public void CommitTransaction()
{
_db.Transaction.Commit();
}
#endregion
當然,這需要一個新的存儲庫類爲每個線程創建的,但這是合理的爲我的項目。
如果存儲庫實現了IHasTransactions
,則使用存儲庫的每種方法都需要調用BeginTransaction()
和EndTransaction()
。爲了使這個呼叫更容易,我想出了以下擴展:
/// <summary>
/// Extensions for spawning and subsequently executing a transaction.
/// </summary>
public static class TransactionExtensions
{
/// <summary>
/// Begins a transaction if the repository implements <see cref="IHasTransactions"/>.
/// </summary>
/// <param name="repository"></param>
public static void BeginTransaction(this IRepository repository)
{
var transactionSupport = repository as IHasTransactions;
if (transactionSupport != null)
{
transactionSupport.BeginTransaction();
}
}
public static void CommitTransaction(this IRepository repository)
{
var transactionSupport = repository as IHasTransactions;
if (transactionSupport != null)
{
transactionSupport.CommitTransaction();
}
}
}
評論感謝!
我不認爲這是DDD精神的解決方案。基本上你已經創建了一個交易腳本來完成域模型的工作。例如,服務不應改變客戶狀態。 – 2013-10-30 09:06:36
代碼中的某些東西必須處理這個業務規則,無論是在這個級別還是更高級別上,在單個TransactionScope中進行更改都允許本地事務或分佈式事務處理事務。如果業務規則規定每當下訂單時都要更新客戶,那麼這是一個處理所有訂單的好地方。 – JoshBerke 2013-11-02 18:12:42