实体框架强制分布式事务

时间:2014-10-31 17:45:51

标签: c# entity-framework transactionscope msdtc

我无法获得以下代码,只使用单个上下文触及单个数据库而不升级到MSDTC,并且在context.SaveChanges()上抛出异常:

public void DeleteGroupDetails(int groupId)
{
    // Note there is no ambient tx
    var thisIsNull = Transaction.Current;

    using (var scope = new TransactionScope())
    {
        var thisIsNotNull = Transaction.Current;

        using (var context = new MyDbEntities())
        {
            var deleted = context.tblGroups.Where(x => x.GroupID == groupId);

            context.tblGroups.RemoveRange(deleted);

            try
            {
                context.SaveChanges();
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
        }

        //scope.Complete();
    }
}

异常是"底层提供程序在Open上失败。 - >合作伙伴事务管理器已禁用其对远程/网络事务的支持。 (HRESULT异常:0x8004D025)"

注意:

  • 这是使用EF 6和SQL Server 2005
  • 由于数据库服务器已锁定,我无法使用MSDTC
  • 我想在POC中使用TransactionScope,因为它将在WCF中运行,它内置了TransactionScope,我不想在事务管理中丢弃我的代码。
  • 类似的项目使用NHibernate而没有这个问题

连接字符串是:

的connectionString ="元数据= RES:// /ResourceAccess.MyDb.csdl|res:// /ResourceAccess.MyDb.ssdl|res://*/ResourceAccess.MyDb。 msl; provider = System.Data.SqlClient; provider connection string =" data source = wil-gvpsqldev01; initial catalog = MyDb; integrated security = True; MultipleActiveResultSets = True; App = EntityFramework""的providerName =" System.Data.EntityClient" />

System.Transactions诊断包括:

<E2ETraceEvent>
    <System>
        <EventID>0</EventID>
        <Type>3</Type>
        <SubType Name="Information">0</SubType>
        <Level>8</Level>
        <TimeCreated SystemTime="2014-10-31T14:39:43.0061489Z" />
        <Source Name="System.Transactions" />
        <Correlation ActivityID="{00000000-0000-0000-0000-000000000000}" />
        <Execution ProcessName="CCS.Host.Console.vshost" ProcessID="64568" ThreadID="13"/>
        <Channel/>
        <Computer>xxx</Computer>
    </System>
        <ApplicationData>
            <TraceData>
                <DataItem>
                    <TraceRecord Severity="Information">
                        <TraceIdentifier>http://msdn.microsoft.com/2004/06/System/Transactions/TransactionCreate</TraceIdentifier>
                        <Description>Transaction Created</Description>
                        <AppDomain>CCS.Host.Console.vshost.exe</AppDomain>
                        <ExtendedData>
                            <TraceSource>[Lightweight]</TraceSource>
                            <TransactionTraceIdentifier>
                            <TransactionIdentifier>2e0814b3-7dd2-4c05-ad69-c3787d95c208:1</TransactionIdentifier>
                            <CloneIdentifier>1</CloneIdentifier>
                            </TransactionTraceIdentifier>
                        </ExtendedData>
                    </TraceRecord>
                </DataItem>
            </TraceData>
        </ApplicationData>
</E2ETraceEvent>
<E2ETraceEvent>
    <System>
        <EventID>0</EventID>
        <Type>3</Type>
        <SubType Name="Information">0</SubType>
        <Level>8</Level>
        <TimeCreated SystemTime="2014-10-31T14:39:43.0181489Z" />
        <Source Name="System.Transactions" />
        <Correlation ActivityID="{00000000-0000-0000-0000-000000000000}" />
        <Execution ProcessName="CCS.Host.Console.vshost" ProcessID="64568" ThreadID="13"/>
        <Channel/>
        <Computer>xxx</Computer>
    </System>
    <ApplicationData>
        <TraceData>
            <DataItem>
                <TraceRecord Severity="Information">
                <TraceIdentifier>http://msdn.microsoft.com/2004/06/System/Transactions/TransactionScopeCreated</TraceIdentifier>
                <Description>TransactionScope Created</Description>
                <AppDomain>CCS.Host.Console.vshost.exe</AppDomain>
                <ExtendedData>
                    <TraceSource>[Base]</TraceSource>
                    <TransactionTraceIdentifier>
                    <TransactionIdentifier>2e0814b3-7dd2-4c05-ad69-c3787d95c208:1</TransactionIdentifier>
                    <CloneIdentifier>2</CloneIdentifier>
                    </TransactionTraceIdentifier>
                    <TransactionScopeResult>CreatedTransaction</TransactionScopeResult>
                </ExtendedData>
                </TraceRecord>
            </DataItem>
        </TraceData>
    </ApplicationData>
</E2ETraceEvent>
<E2ETraceEvent>
    <System>
        <EventID>0</EventID>
        <Type>3</Type>
        <SubType Name="Information">0</SubType>
        <Level>8</Level>
        <TimeCreated SystemTime="2014-10-31T14:39:49.1921489Z"/>
        <Source Name="System.Transactions"/>
        <Correlation ActivityID="{00000000-0000-0000-0000-000000000000}"/>
        <Execution ProcessName="CCS.Host.Console.vshost" ProcessID="64568" ThreadID="13"/>
        <Channel/>
        <Computer>ccc</Computer>
    </System>
    <ApplicationData>
        <TraceData>
            <DataItem>
                <TraceRecord Severity="Information">
                    <TraceIdentifier>http://msdn.microsoft.com/2004/06/System/Transactions/Enlistment</TraceIdentifier>
                    <Description>Enlistment Created</Description>
                    <AppDomain>CCS.Host.Console.vshost.exe</AppDomain>
                    <ExtendedData>
                        <TraceSource>[Lightweight]</TraceSource>
                        <EnlistmentTraceIdentifier>
                            <ResourceManagerId>00000000-0000-0000-0000-000000000000</ResourceManagerId>
                            <TransactionTraceIdentifier>
                                <TransactionIdentifier>2e0814b3-7dd2-4c05-ad69-c3787d95c208:1</TransactionIdentifier>
                                <CloneIdentifier>2</CloneIdentifier>
                            </TransactionTraceIdentifier>
                            <EnlistmentIdentifier>0</EnlistmentIdentifier>
                        </EnlistmentTraceIdentifier>
                        <EnlistmentType>PromotableSinglePhase</EnlistmentType>
                        <EnlistmentOptions>None</EnlistmentOptions>
                    </ExtendedData>
                </TraceRecord>
            </DataItem>
        </TraceData>
    </ApplicationData>
</E2ETraceEvent>
<E2ETraceEvent >
    <System >
        <EventID>0</EventID>
        <Type>3</Type>
        <SubType Name="Error">0</SubType>
        <Level>2</Level>
        <TimeCreated SystemTime="2014-10-31T14:39:50.8941489Z" />
        <Source Name="System.Transactions" />
        <Correlation ActivityID="{00000000-0000-0000-0000-000000000000}" />
        <Execution ProcessName="CCS.Host.Console.vshost" ProcessID="64568" ThreadID="13" />
        <Channel/>
        <Computer>ccc</Computer>
    </System>
    <ApplicationData>
        <TraceData>
            <DataItem>
                <TraceRecord  Severity="Error">
                    <TraceIdentifier>http://msdn.microsoft.com/2004/06/System/Transactions/TransactionException</TraceIdentifier>
                    <Description>TransactionException Thrown</Description>
                    <AppDomain>CCS.Host.Console.vshost.exe</AppDomain>
                    <ExtendedData xmlns="http://schemas.microsoft.com/2004/03/Transactions/TransactionExceptionTraceRecord">
                        <TraceSource>[Distributed]</TraceSource>
                        <ExceptionMessage>The partner transaction manager has disabled its support for remote/network transactions. (Exception from HRESULT: 0x8004D025)</ExceptionMessage>
                    </ExtendedData>
                </TraceRecord>
            </DataItem>
        </TraceData>
    </ApplicationData>
</E2ETraceEvent>
<E2ETraceEvent >
    <System >
        <EventID>0</EventID>
        <Type>3</Type>
        <SubType Name="Warning">0</SubType>
        <Level>4</Level>
        <TimeCreated SystemTime="2014-10-31T14:39:50.9591489Z" />
        <Source Name="System.Transactions" />
        <Correlation ActivityID="{00000000-0000-0000-0000-000000000000}" />
        <Execution ProcessName="CCS.Host.Console.vshost" ProcessID="64568" ThreadID="13" />
        <Channel/>
        <Computer>ccc</Computer>
    </System>
    <ApplicationData>
        <TraceData>
            <DataItem>
                <TraceRecord xmlns="http://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord" Severity="Warning">
                    <TraceIdentifier>http://msdn.microsoft.com/2004/06/System/Transactions/EnlistmentCallbackNegative</TraceIdentifier>
                    <Description>Enlistment Callback Negative</Description>
                    <AppDomain>CCS.Host.Console.vshost.exe</AppDomain>
                    <ExtendedData >
                        <TraceSource>[Lightweight]</TraceSource>
                        <EnlistmentTraceIdentifier>
                        <ResourceManagerId>00000000-0000-0000-0000-000000000000</ResourceManagerId>
                        <TransactionTraceIdentifier>
                            <TransactionIdentifier>2e0814b3-7dd2-4c05-ad69-c3787d95c208:1</TransactionIdentifier>
                            <CloneIdentifier>2</CloneIdentifier>
                        </TransactionTraceIdentifier>
                        <EnlistmentIdentifier>0</EnlistmentIdentifier>
                        </EnlistmentTraceIdentifier><EnlistmentCallback>Aborted</EnlistmentCallback>
                    </ExtendedData>
                </TraceRecord>
            </DataItem>
        </TraceData>
    </ApplicationData>
</E2ETraceEvent>
<E2ETraceEvent >
    <System >
        <EventID>0</EventID>
        <Type>3</Type>
        <SubType Name="Warning">0</SubType>
        <Level>4</Level>
        <TimeCreated SystemTime="2014-10-31T14:39:50.9601489Z" />
        <Source Name="System.Transactions" />
        <Correlation ActivityID="{00000000-0000-0000-0000-000000000000}" />
        <Execution ProcessName="CCS.Host.Console.vshost" ProcessID="64568" ThreadID="13" />
        <Channel/>
        <Computer>ccc</Computer>
    </System>
    <ApplicationData>
        <TraceData>
            <DataItem>
                <TraceRecord Severity="Warning">
                    <TraceIdentifier>http://msdn.microsoft.com/2004/06/System/Transactions/TransactionAborted</TraceIdentifier>
                    <Description>Transaction Aborted</Description>
                    <AppDomain>CCS.Host.Console.vshost.exe</AppDomain>
                    <ExtendedData >
                        <TraceSource>[Lightweight]</TraceSource>
                        <TransactionTraceIdentifier>
                        <TransactionIdentifier>2e0814b3-7dd2-4c05-ad69-c3787d95c208:1</TransactionIdentifier>
                        </TransactionTraceIdentifier>
                    </ExtendedData>
                </TraceRecord>
            </DataIt

1 个答案:

答案 0 :(得分:4)

问题在于EF关闭获取groupId的实体然后删除实体之间的连接。这导致了升级。解决方法是控制连接的打开和关闭:

http://msdn.microsoft.com/en-us/data/dn456849.aspx

  

EF6和未来版本中的行为

     

对于EF6和未来的版本,我们采取的方法是,如果   调用代码选择通过调用打开连接   context.Database.Connection.Open()然后它有一个很好的理由   所以框架将假设它想要控制开放   并关闭连接,将不再关闭连接   自动。

我能找到的这种行为的唯一文档是此博客条目中的表,表示如果有多个连接,2008之前的SQL Server版本将升级:

https://petermeinl.wordpress.com/2011/03/13/avoiding-unwanted-escalation-to-distributed-transactions/

这是我降落的地方:

using System;
using System.Data;

namespace Services.ResourceAccess
{
    public class ResourceAccess : IDisposable
    {
        private readonly Lazy<MyDbEntities> _context;

        public ResourceAccess()
        {
            _context = new Lazy<MyDbEntities>(() =>
            {
                var context = new MyDbEntities();

                context.Database.Connection.Open();

                return context;
            });
        }

        public void DeleteGroupDetails(int groupId)
        {
            var deleted = _context.Value.tblGroupDetails.Where(x => x.GroupID == groupId);

            _context.Value.tblGroupDetails.RemoveRange(deleted);

            _context.Value.SaveChanges();
        }

        public void Dispose()
        {
            if (_context.IsValueCreated)
            {
                if (_context.Value.Database.Connection.State == ConnectionState.Open)
                {
                    _context.Value.Database.Connection.Close();
                }
            }
        }
    }
}