我们通过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;
}
}
答案 0 :(得分:7)
实体框架中有no bulk insert。您在100条记录之后调用SaveChanges
,但它将执行100个单独的插入,每个插入数据库往返。
设置事务超时还取决于在机器级别配置的事务max timeout(我认为默认值为10分钟)。在手术失败之前需要多长时间?
您可以做的最好的方法是使用常见的ADO.NET或批量插入重写插入逻辑。
顺便说一下。 throw exception
和throw e
?这是rethrow exceptions的错误方式。
重要编辑:
SaveChanges(SaveOptions.None)
!!!表示保存后不接受更改,因此所有记录仍处于添加状态。因此,对SaveChanges
的第一次调用将插入前100条记录。第二个调用将再次插入100个+下一个100,第三个调用将插入第一个200 +下一个100,等等。
答案 1 :(得分:1)
我有完全相同的问题。我每次都使用EF代码插入批量1000条记录。
我从一开始就在工作,msdTC的一个小问题是我允许远程客户端和管理员,但之后就可以了。我做了很多工作,但有一天它只是停止工作。
我正在
与当前连接关联的事务已完成但尚未处理。必须先处理事务,然后才能使用连接执行SQL语句。
非常!有时错误会发生变化。我怀疑是msDTC不知何故,奇怪的行为。 我现在正在改变不使用TransactionScope!
我讨厌它什么时候起作用而且停止了。我也尝试在一个vm中运行它,另一个浪费时间浪费... 我的代码:
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;
}
答案 2 :(得分:0)
由于TransactionScope默认的最大超时时间超时,请检查machine.config。
点击此链接: