我从这里开始:Implementing LINQ-to-SQL transactions through WCF
从那以后我来到了以下。我使用basicHttpBinding用于遗留,我的WCF客户端是非托管C ++(gSOAP)。所以我使用ASP.NET Session并在WCF上启用aspNetCompatibilityMode。这有效,所以现在我可以正确处理会话。
现在我的想法是为每个会话分配单独的LINQ-to-SQL DataContext,并以此方式实现事务行为。我想要做的是将DataContext实例存储在Session中,在不调用SubmitChanges()的情况下执行所有插入操作,然后只调用SubmitChanges()一次以提交事务。
不幸的是,LINQ-to-SQL中存在一个错误,它阻止您在调用SubmitChanges()之前从DataContext中获取以前插入的数据(请参阅here)我需要这样做,因为在插入招标文件和标题之前,我需要检索招标本身。所以这不起作用(至少没有完全重构代码并且失去了大部分LINQ-to-SQL的美感......)
现在的问题是:如何通过WCF正确实现per-DataContext事务?我不能从客户端传播TransactionScope,因为客户端是不受管理的。由于上面的错误,我无法使用内部LINQ-to-SQL事务。我唯一拥有的是ASP.NET Session(可以工作)。也许我可以以某种方式将TransactionScope存储在Session中?
答案 0 :(得分:1)
就个人而言,我会尝试在单个工作单元上工作。这可能意味着客户端打包完整的请求并将其作为原子操作提交,或者它可能意味着您通过会话单独执行此操作 - 即您缓冲多个调用的“内容”,但只有在你拥有所需的一切时才开始做某事。
无论哪种方式,最终结果是您最终在单个实现上运行您的工作单元,这应该使db-transactions或环境(TransactionScope
)事务正常工作。环境事务(在您的场景中)的优势在于它可以跨多个数据上下文工作,但我希望能够修复Single
调用(根据相关问题),而不必太过头痛
或者等到.NET 4.0,我确信这个有问题的bug已经解决了。好的,最后可能在短期内没用...
答案 1 :(得分:0)
在我看来,重要的是你重复使用相同的连接和事务。我将使用DataContext上的构造函数来获取现有连接。会话启动后,通过分配连接和事务来开始事务。将连接和事务存储在会话中。然后在每次调用时,使用相同的连接和事务重新创建DataContext。完成后,调用提交事务的方法。在会话超时时,您需要确保将事务回滚。
public bool CreateTransaction()
{
var connection = new SqlConnection( connectionString );
var transaction = connection.BeginTransaction();
Session["DBConnection"] = connection;
Session["DBTransaction"] = transaction;
return true;
}
private DBDataContext CreateContextFromSession()
{
if (Session["DBConnection"] == null)
throw new NullReferenceException( "No connection available for transaction." );
if (Session["DBTransaction"] == null)
throw new NullReferenceException( "No transaction available." );
var context = new DBDataContext( (IDbConnection)Session["DBConnection"] );
context.Transaction = (DbTransaction)Session["DBTransaction"];
return context;
}
public Tender CreateTender( ... )
{
var context = CreateContextFromSession();
var tender = new Tender { ... };
context.Tenders.InsertOnSubmit( tender );
context.SubmitChanges();
return tender;
}
public void CommitTransaction()
{
var transaction = (DbTransaction)Session["DBTransaction"];
transaction.Commit();
Session.Remove( "DBTransaction" );
var connection = (IDbConnection)Session["DBConnection"];
connection.Close();
Session.Remove( "DBConnection" );
}