Entity framework EntityFramework 4.0的大容量插入导致事务中止

Entity framework EntityFramework 4.0的大容量插入导致事务中止,entity-framework,transactions,Entity Framework,Transactions,我们通过WCF从客户端(Silverlight)接收到一个文件,在服务器端我解析这个文件。文件中的每一行都被转换成一个对象并存储到数据库中。如果文件非常大(10000个或更多条目),则会出现以下错误(MSSQLEXPRESS): 与当前连接关联的事务已完成,但尚未处理。必须先释放事务,然后才能使用连接执行SQL语句 我尝试了很多(TransactionOptions超时设置等),但都不起作用。上面的异常消息要么是在处理了3000个对象后出现的,有时是在处理了6000个对象后出现的,但我无法成功地

我们通过WCF从客户端(Silverlight)接收到一个文件,在服务器端我解析这个文件。文件中的每一行都被转换成一个对象并存储到数据库中。如果文件非常大(10000个或更多条目),则会出现以下错误(MSSQLEXPRESS):

与当前连接关联的事务已完成,但尚未处理。必须先释放事务,然后才能使用连接执行SQL语句

我尝试了很多(TransactionOptions超时设置等),但都不起作用。上面的异常消息要么是在处理了3000个对象后出现的,有时是在处理了6000个对象后出现的,但我无法成功地处理所有对象

我附上了我的资料,希望有人能想出一个主意,并能帮助我:

public xxxResponse SendLogFile (xxxRequest request
{
   const int INTERMEDIATE_SAVE = 100;



   using (var context = new EntityFramework.Models.Cubes_ServicesEntities())
   {
            // start a new transactionscope with the timeout of 0 (unlimited time for developing purposes)
            using (var transactionScope = new TransactionScope(TransactionScopeOption.RequiresNew,
            new TransactionOptions
            {
                IsolationLevel = System.Transactions.IsolationLevel.Serializable,
                Timeout = TimeSpan.FromSeconds(0)
            }))
            {
                try
                {
                    // open the connection manually to prevent undesired close of DB
                    // (MSDTC)
                    context.Connection.Open();
                    int timeout = context.Connection.ConnectionTimeout;

                    int Counter = 0;

                    // read the file submitted from client
                    using (var reader = new StreamReader(new MemoryStream(request.LogFile)))
                    {
                        try
                        {
                            while (!reader.EndOfStream)
                            {
                                Counter++;
                                Counter2++;
                                string line = reader.ReadLine();
                                if (String.IsNullOrEmpty(line)) continue;

                                // Create a new object
                                DomainModel.LogEntry le = CreateLogEntryObject(line);

                                // an attach it to the context, set its state to added.
                                context.AttachTo("LogEntry", le);
                                context.ObjectStateManager.ChangeObjectState(le, EntityState.Added);

                                // while not 100 objects were attached, go on
                                if (Counter != INTERMEDIATE_SAVE) continue;

                                // after 100 objects, make a call to SaveChanges.
                                context.SaveChanges(SaveOptions.None);
                                Counter = 0;
                            }
                        }
                        catch (Exception exception)
                        {
                            // cleanup
                            reader.Close();
                            transactionScope.Dispose();
                            throw exception;

                        }

                    }
                    // do a final SaveChanges
                    context.SaveChanges();
                    transactionScope.Complete();
                    context.Connection.Close();
                }
                catch (Exception e)
                {
                    // cleanup
                    transactionScope.Dispose();
                    context.Connection.Close();
                    throw e;
                }
            }

            var response = CreateSuccessResponse<ServiceSendLogEntryFileResponse>("SendLogEntryFile successful!");
            return response;
        }
    }
public xxx响应发送日志文件(xxx请求)
{
const int INTERMEDIATE_SAVE=100;
使用(var context=new EntityFramework.Models.Cubes\u servicestentities())
{
//启动一个新的transactionscope,超时为0(用于开发的时间不限)
使用(var transactionScope=new transactionScope)(TransactionScopeOption.RequiresNew,
新交易选项
{
IsolationLevel=System.Transactions.IsolationLevel.Serializable,
超时=TimeSpan.FromSeconds(0)
}))
{
尝试
{
//手动打开连接以防止意外关闭DB
//(MSDTC)
context.Connection.Open();
int timeout=context.Connection.ConnectionTimeout;
int计数器=0;
//读取从客户端提交的文件
使用(var reader=newstreamreader(newmemoryStream(request.LogFile)))
{
尝试
{
而(!reader.EndOfStream)
{
计数器++;
计数器2++;
字符串行=reader.ReadLine();
如果(String.IsNullOrEmpty(line))继续;
//创建一个新对象
DomainModel.LogEntry le=CreateLogEntryObject(行);
//若要将其附加到上下文,请将其状态设置为“已添加”。
上下文。附件(“日志条目”,le);
context.ObjectStateManager.ChangeObjectState(le,EntityState.Add);
//虽然没有连接100个对象,但请继续
如果(计数器!=中间保存)继续;
//在100个对象之后,调用SaveChanges。
context.SaveChanges(SaveOptions.None);
计数器=0;
}
}
捕获(异常)
{
//清理
reader.Close();
transactionScope.Dispose();
抛出异常;
}
}
//做最后一次保存更改
SaveChanges();
transactionScope.Complete();
context.Connection.Close();
}
捕获(例外e)
{
//清理
transactionScope.Dispose();
context.Connection.Close();
投掷e;
}
}
var response=CreateSuccessResponse(“SendLogEntryFile successful!”);
返回响应;
}
}
实体框架中有。您在100条记录之后调用
SaveChanges
,但它将执行100个单独的插入,每个插入都有数据库往返

设置事务超时也取决于在机器级别配置的事务(我认为默认值为10分钟)。在操作失败之前需要多长时间

最好的方法是使用普通ADO.NET或大容量插入重写插入逻辑

顺便说一句,
抛出异常
抛出e
?这是不正确的方法

重要编辑:

SaveChanges(SaveOptions.None)
!!!表示保存后不接受更改,因此所有记录仍处于添加状态。因此,对
SaveChanges
的第一次调用将插入前100条记录。第二次调用将再次插入前100条+下100条,第三次调用将插入前200条+下100条,以此类推。

实体框架中有。您调用
SaveChanges
在100条记录之后进行更改,但它将执行100次单独的插入,每次插入都会执行数据库往返

设置事务超时也取决于在机器级别配置的事务(我认为默认值为10分钟)。在操作失败之前需要多长时间

最好的方法是使用普通ADO.NET或大容量插入重写插入逻辑

顺便说一句,
抛出异常
抛出e
?这是不正确的方法

重要编辑:


SaveChanges(SaveOptions.None)
!!!表示保存后不接受更改,因此所有记录仍处于添加状态。因此,第一次调用
SaveChanges
将插入前100条记录。第二次调用将再次插入前100条+下100条,第三次调用将插入前200条+下100条,以此类推。

由于TransactionScope默认值为Ma,因此超时ximum Timeout,请检查machine.config以获取该信息

    private void AddTicks(FileHelperTick[] fhTicks)
    {
        List<ForexEF.Entities.Tick> Ticks = new List<ForexEF.Entities.Tick>();

        var str = LeTicks(ref fhTicks, ref Ticks);

        using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions()
        {
            IsolationLevel = System.Transactions.IsolationLevel.Serializable,
            Timeout = TimeSpan.FromSeconds(180)
        }))
        {
            ForexEF.EUR_TICKSContext contexto = null;                
            try
            {
                contexto = new ForexEF.EUR_TICKSContext();

                contexto.Configuration.AutoDetectChangesEnabled = false;

                int count = 0;
                foreach (var tick in Ticks)
                {
                    count++;
                    contexto = AddToContext(contexto, tick, count, 1000, true);
                }
                contexto.SaveChanges();
            }
            finally
            {
                if (contexto != null)
                    contexto.Dispose();
            }
            scope.Complete();
        }   
    }

    private ForexEF.EUR_TICKSContext AddToContext(ForexEF.EUR_TICKSContext contexto, ForexEF.Entities.Tick tick, int count, int commitCount, bool recreateContext)
    {
        contexto.Set<ForexEF.Entities.Tick>().Add(tick);

        if (count % commitCount == 0)
        {
            contexto.SaveChanges();
            if (recreateContext)
            {
                contexto.Dispose();
                contexto = new ForexEF.EUR_TICKSContext();
                contexto.Configuration.AutoDetectChangesEnabled = false;
            }
        }

        return contexto;
    }