我在SQL Server 2008上使用EF5.0。我在同一服务器实例上有两个数据库。我需要更新两个数据库上的表,并希望它们是同一个事务。所以我使用了TransactionScope。以下是代码 -
public void Save()
{
var MSObjectContext = ((IObjectContextAdapter)MSDataContext).ObjectContext;
var AWObjectContext = ((IObjectContextAdapter)AwContext).ObjectContext;
using (var scope = new TransactionScope(TransactionScopeOption.Required,
new TransactionOptions
{
IsolationLevel = IsolationLevel.ReadUncommitted
}))
{
MSObjectContext.SaveChanges(SaveOptions.DetectChangesBeforeSave);
AWObjectContext.SaveChanges(SaveOptions.DetectChangesBeforeSave);
scope.Complete();
}
}
当我使用上面的代码时,事务被提升为DTC。在互联网上搜索后,我发现这是因为两个不同的连接串/连接。但我不明白的是,如果我在一个数据库上编写存储过程,该数据库更新不同数据库中的表(在同一服务器上),则不需要DTC。那么为什么EF或TransactionScope会将其推广到DTC?还有其他解决方法吗?
请告知
提前致谢
西
答案 0 :(得分:6)
使用普通DbConnection
,您可以使用相同的连接字符串(使用您喜欢的任何数据库)阻止同一服务器上多个数据库的DTC升级,并手动更改打开的连接对象上的数据库,如下所示:
using (var tx = new TransactionScope())
{
using (var conn = new SqlConnection(connectStr))
{
conn.Open();
new SqlCommand("INSERT INTO atest VALUES (1)", conn).ExecuteNonQuery();
}
using (var conn = new SqlConnection(connectStr))
{
conn.Open();
conn.ChangeDatabase("OtherDB");
new SqlCommand("INSERT INTO btest VALUES (2)", conn).ExecuteNonQuery();
}
tx.Complete();
}
这不会升级为DTC,但如果您为connectStr
使用了不同的值,则会这样。
我不熟悉EF以及它如何管理连接和上下文,但使用上述见解,您可以通过执行conn.ChangeDatabase(..)
然后创建像{{3}这样的上下文来避免DTC升级}。
但请注意,即使使用共享连接字符串,只要您同时打开两个连接,DTC就会参与其中,就像在此修改示例中一样:
using (var tx = new TransactionScope())
{
using (var conn = new SqlConnection(mssqldb))
{
conn.Open();
new SqlCommand("INSERT INTO atest VALUES (1)", conn).ExecuteNonQuery();
using (var conn2 = new SqlConnection(mssqldb))
{
conn2.Open();
conn2.ChangeDatabase("otherdatabase");
new SqlCommand("INSERT INTO btest VALUES (2)", conn2).ExecuteNonQuery();
}
}
tx.Complete();
}