我有一个WCF服务,用于向数据库添加投标,即MS SQL Server 2005.WCF使用LINQ-to-SQL。
每个招标都可以有很多文件和很多项目。客户可以为每个服务调用添加一个对象。也就是说,做这样的事情:
TendersServiceClient service = new TenderServiceClient();
service.BeginTransaction();
// Adding a new tender
service.AddTender(TenderDTO tenderInfo);
// Adding tender's documents
foreach (DocumentDTO documentInfo in documents)
service.AddTenderDocument(tenderInfo.TenderID, documentInfo);
// Adding tender's items
foreach (ItemDTO itemInfo in items)
service.AddTenderItem(tenderInfo.TenderID, itemInfo);
service.CommitTransaction();
注意BeginTransaction()和CommitTransaction()。也就是说,所有上述过程必须完全成功或完全回滚。例如,如果其中一个项目无法插入,那么整个招标就不应该存在......
所以问题是如何实现这种交易。问题是WCF当然是无国籍的。因此,为每个服务调用创建了新的DataContext。如果我使用静态DataContext,那么我将能够使用其内置的事务功能,但是如何处理其他可以尝试同时添加另一个招标的客户(当然,他们必须在这笔交易之外)?
所以请帮助我用某种设计模式来实现这一目标。我可以自由更改服务和客户端的代码,所以请随意使用您的建议=)
答案 0 :(得分:2)
您是否控制了服务的界面?
如果是这样,那么优雅的解决方案肯定是服务在单个方法中接受聚合Tender对象,而不是现在拥有的chatty方法。然后,投标将具有项目和文档作为子集合,并且数据访问代码可以更容易地处理单个事务中的所有更新。
除非我误解,否则它似乎非常类似于Order / OrderDetails场景,其中适用相同的逻辑。
答案 1 :(得分:1)
首先,你必须在这里使用交易服务电话 - 因为你有一个“初始化”电话,一堆中间电话,然后可能有一个结束所有电话,我建议你看看方法的OperationContract上的“IsInitiating”和“IsTerminating”属性 - 这将允许您指定一个方法来启动会话,并指定一个方法来完成它。
接下来,请确保将服务配置为事务服务,方法是将“TransactionFlow”属性放在服务或所有操作上 - 无论您喜欢哪种操作。
在您的客户端代码中,您必须使用System.Transactions创建一个TransactionScope,它将包装您的服务调用。这是一个轻量级或完全两阶段的分布式事务协调器 - 具体取决于您的调用的详细信息。
沿着这些方向:
1)将您的绑定标记为事务性:
<bindings>
<wsHttpBinding>
<binding name="TransactionalWsHttp" transactionFlow="true" />
</wsHttpBinding>
</bindings>
2)服务合同:
[ServiceContract]
public interface ITenderService
{
// method to start your submission process
[OperationContract(IsInitiating=true, IsTerminating=false)]
[TransactionFlow(TransactionFlowOption.Mandatory]
public void StartTenderProcess();
// all your other methods "in between"
[OperationContract(IsInitiating=false, IsTerminating=false)]
[TransactionFlow(TransactionFlowOption.Mandatory]
public void AddTender()
[OperationContract(IsInitiating=false, IsTerminating=false)]
[TransactionFlow(TransactionFlowOption.Mandatory]
public void AddTenderDocument()
[OperationContract(IsInitiating=false, IsTerminating=false)]
[TransactionFlow(TransactionFlowOption.Mandatory]
public void AddTenderItem()
...
// method to end your submission process
[OperationContract(IsInitiating=false, IsTerminating=true)]
[TransactionFlow(TransactionFlowOption.Mandatory]
public void FinishTenderProcess();
}
3)在您的客户代码中:
using (TransactionScope ts = new TransactionScope())
{
serviceClient.StartTenderProcess();
.....
serviceClient.FinishTenderProcess();
ts.Complete(); // Transaction Commit
}
这有助于你暂时开始吗?
马克