Can*_*hiu 15 c# transactionscope linq-to-sql
我想用一个事务中的新记录替换DB中的现有记录.使用TransactionScope,我有
using ( var scope = new TransactionScope())
{
db.Tasks.DeleteAllOnSubmit(oldTasks);
db.Tasks.SubmitChanges();
db.Tasks.InsertAllOnSubmit(newTasks);
db.Tasks.SubmitChanges();
scope.Complete();
}
Run Code Online (Sandbox Code Playgroud)
我的节目扔了
System.InvalidOperationException: Cannot add an entity that already exists.
Run Code Online (Sandbox Code Playgroud)
经过一些反复试验,我发现罪魁祸首在于删除和插入之间没有任何其他执行指令.如果我在第一个SubmitChanges()和InsertAllOnSubmit()之间插入其他代码,一切正常.谁能解释为什么会这样?这非常令人担忧.
我尝试了另一个来更新对象:
IEnumerable<Task> tasks = ( ... some long query that involves multi tables )
.AsEnumerable()
.Select( i =>
{
i.Task.Duration += i.LastLegDuration;
return i.Task;
}
db.SubmitChanges();
Run Code Online (Sandbox Code Playgroud)
这既不起作用.db没有获取任务的任何更改.
编辑:
此行为似乎与交易无关.最后,我采用了效率极低的更新:
newTasks.ForEach( t =>
{
Task attached = db.Tasks.Single( i => ... use primary id to look up ... );
attached.Duration = ...;
... more updates, Property by Property ...
}
db.SubmitChanges();
Run Code Online (Sandbox Code Playgroud)
您可以尝试通过选择要更新的 Id 列表并检查该列表是否包含每一项来一次更新多行,而不是插入和删除或进行多个查询。
另外,请确保将事务标记为完成,以向事务管理器指示所有资源的状态是一致的,并且可以提交事务。
Dictionary<int,int> taskIdsWithDuration = getIdsOfTasksToUpdate(); //fetch a dictionary keyed on id's from your long query and values storing the corresponding *LastLegDuration*
using (var scope = new TransactionScope(TransactionScopeOption.Required))
{
var tasksToUpdate = db.Tasks.Where(x => taskIdsWithDuration.Keys.Contains(x.id));
foreach (var task in tasksToUpdate)
{
task.duration1 += taskIdsWithDuration[task.id];
}
db.SaveChanges();
scope.Complete();
}
Run Code Online (Sandbox Code Playgroud)
根据您的情况,如果您的表非常大并且要更新的项目数相当小,您可以反转搜索,以利用索引。如果是这种情况,您现有的更新查询应该可以正常工作,所以我怀疑您是否需要反转它。