C# 实体框架中记录的并发访问
我正在寻找一个优雅的解决方案来处理实体框架中的并发冲突 我的给药表格有一些列,如药物名称、剂量、频率、给药方法、注释等。操作员可以在查看记录后修改剂量、频率、给药方法等字段,也可以添加注释 我们正在使用SQL Server数据库 我添加了一列LastUpdated类型的timestamp。我使用此列引发DbUpdateConcurrencyException。在实体设计器中,LastUpdated列的ConcurrencyMode已设置为Fixed 我的控制器类中的代码段:C# 实体框架中记录的并发访问,c#,sql,entity-framework,C#,Sql,Entity Framework,我正在寻找一个优雅的解决方案来处理实体框架中的并发冲突 我的给药表格有一些列,如药物名称、剂量、频率、给药方法、注释等。操作员可以在查看记录后修改剂量、频率、给药方法等字段,也可以添加注释 我们正在使用SQL Server数据库 我添加了一列LastUpdated类型的timestamp。我使用此列引发DbUpdateConcurrencyException。在实体设计器中,LastUpdated列的ConcurrencyMode已设置为Fixed 我的控制器类中的代码段: // drugId
// drugId and strNotes are passed from edit screen
DataAccessLayer.Dal dal= new DataAccessLayer.Dal();
// Select record
DrugDetail drugDetail = (from drugRow in dal.DrugDetails
where drugRow.id == drugId
select drugRow).ToList<DrugDetail>()[0];
// Assign notes
drugDetail.Notes = strNotes;
try
{
dal.SaveChanges();
}
catch(DbUpdateConcurrencyException ex)
{
((IObjectContextAdapter)dal).ObjectContext.
Refresh(System.Data.Objects.RefreshMode.StoreWins, drugDetail);
// Set the notes data again
drugDetail.Notes = strNotes;
// Is it possible that DbUpdateConcurrencyException occur again here
dal.SaveChanges();
}
并发冲突随时可能发生 使用循环重复该过程,直到可以保存更改而不会出现并发冲突
DataAccessLayer.Dal dal= new DataAccessLayer.Dal();
//Select record
DrugDetail drugDetail = (from drugRow in dal.DrugDetails
where drugRow.id == drugId
select drugRow).Single();
int count = 0;
while ( true )
{
//Assign notes
drugDetail.Notes = strNotes;
try
{
dal.SaveChanges();
break;
}
catch(DbUpdateConcurrencyException)
{
count++;
if ( count > 10 )
throw;
((IObjectContextAdapter)dal).ObjectContext.
Refresh(System.Data.Objects.RefreshMode.StoreWins, drugDetail);
}
}
听起来,您正试图自行开发自己的乐观并发机制。这可能不会很好地工作,因为数据总是有可能发生更改,即使是在调用SaveChanges和SQL Server将数据写入表之间的很短时间内,而数据位仍在传输中 您需要特殊的设置才能使其正常工作。如果您使用的是实体框架,则需要将LastUpdated列设置为并发令牌,如下所示:
modelBuilder.Entity<Department>().Property(p => p.LastUpdated).IsConcurrencyToken();
通过这种方式,EF可以在同一个原子事务中检查时间戳并更新数据,从而构造SQL
如果您坚持自己做,您可以将读取和保存打包到您自己的事务中,请务必选择适当的。但是,这将大大降低效率,并延长行/页/表被锁定的时间,如果用户太多,这将影响性能
可以找到更多信息。显示DrugDetail类以及该属性和/或FluentAPI的配置。顺便说一句:如果可能的话。ToList[0];将返回NULL,考虑将它改为to.istr.FrestRealStudio;@太好了,为什么是托利斯特,第一名,而不仅仅是第一名?我会使用Single/SingleOrDefault,因为这是您对查询的真正期望-一个项目或什么都没有每个读/写操作之间可能会发生并发冲突可以移动drugDetail。注释脱离循环?好建议。我确信在循环中保持SaveChanges的技巧将使我能够在每次尝试中跟踪异常。谢谢。我已经为EDMX图表中的LastUpdated字段定义了并发模式=修复。我的理解是EF将确保它不会用LastUpdated数据的旧时间戳值更新表中的行。我会把你建议的清单通读一遍。谢谢你给我指路。
modelBuilder.Entity<Department>().Property(p => p.LastUpdated).IsConcurrencyToken();
bool saveFailed;
do
{
saveFailed = false;
try
{
context.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
saveFailed = true;
// Get the current entity values and the values in the database
var entry = ex.Entries.Single();
var currentValues = entry.CurrentValues;
var databaseValues = entry.GetDatabaseValues();
// Choose an initial set of resolved values. In this case we
// make the default be the values currently in the database.
var resolvedValues = databaseValues.Clone();
// Have the user choose what the resolved values should be
HaveUserResolveConcurrency(currentValues, databaseValues, resolvedValues);
// Update the original values with the database values and
// the current values with whatever the user choose.
entry.OriginalValues.SetValues(databaseValues);
entry.CurrentValues.SetValues(resolvedValues);
}
} while (saveFailed);