Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/308.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 实体框架中记录的并发访问_C#_Sql_Entity Framework - Fatal编程技术网

C# 实体框架中记录的并发访问

C# 实体框架中记录的并发访问,c#,sql,entity-framework,C#,Sql,Entity Framework,我正在寻找一个优雅的解决方案来处理实体框架中的并发冲突 我的给药表格有一些列,如药物名称、剂量、频率、给药方法、注释等。操作员可以在查看记录后修改剂量、频率、给药方法等字段,也可以添加注释 我们正在使用SQL Server数据库 我添加了一列LastUpdated类型的timestamp。我使用此列引发DbUpdateConcurrencyException。在实体设计器中,LastUpdated列的ConcurrencyMode已设置为Fixed 我的控制器类中的代码段: // drugId

我正在寻找一个优雅的解决方案来处理实体框架中的并发冲突

我的给药表格有一些列,如药物名称、剂量、频率、给药方法、注释等。操作员可以在查看记录后修改剂量、频率、给药方法等字段,也可以添加注释

我们正在使用SQL Server数据库

我添加了一列LastUpdated类型的timestamp。我使用此列引发DbUpdateConcurrencyException。在实体设计器中,LastUpdated列的ConcurrencyMode已设置为Fixed

我的控制器类中的代码段:

// 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);