使用实体框架和存储过程进行并发检查

Posted

技术标签:

【中文标题】使用实体框架和存储过程进行并发检查【英文标题】:Concurrency checks with Entity Framework and Stored Procedures 【发布时间】:2018-02-27 23:10:34 【问题描述】:

我正在使用实体框架并通过存储过程(每个客户端请求)操作 sqlserver 数据库中的数据。 通过存储过程从数据库中提取数据,这些存储过程的结果将填充到 Winforms 应用程序中的 SQLite 数据库。

SQLite 用于额外查询和更改数据,然后在用户同步时通过更新存储过程推送回 sql server db

所有存储过程都在 sql server 上(在应用程序中没有文本/行 sql)

我面临多个用户可能尝试更新同一字段的情况,这给我带来了 2 个问题。

    如果它们同时调用相同的存储过程(选择或更新)。 我不确定从编程级别来看我的选择是什么,我无权更改服务器。

    如果他们尝试更新的字段已经更新。

对于问题 2,我正在尝试通过对修改进行日期标记来构建检查。 IE。当用户同步 sql server 将该同步日期添加到日期修改列时,如果另一个用户尝试修改同一字段,我想检查他的 sqlite db 上修改的日期并将其与 sql server 中修改的日期进行比较,如果 sql server 的修改日期较新,保留 sql server 值,如果同步用户的修改日期较新,请使用他的...

我研究了在客户端获胜的情况下解决乐观并发问题。

using (var context = new BloggingContext()) 
 
var blog = context.Blogs.Find(1); 
blog.Name = "The New ADO.NET Blog"; 

bool saveFailed; 
do 
 
    saveFailed = false; 
    try 
     
        context.SaveChanges(); 
     
    catch (DbUpdateConcurrencyException ex) 
     
        saveFailed = true; 

        // Update original values from the database 
        var entry = ex.Entries.Single(); 
        entry.OriginalValues.SetValues(entry.GetDatabaseValues()); 
     

 while (saveFailed); 

但这似乎只在您使用实体框架直接查询数据库时有效,而不是在您想通过存储过程更新时有效。

我可以使用什么来执行这些类型的检查?

【问题讨论】:

【参考方案1】:

好的,这可能不是最好的解决方案,但这是我能够想出的,虽然最初没有经过广泛测试,但似乎还可以。

我不会将此标记为答案,但这是我根据上述问题所做的工作。

    同时调用存储过程,为事务创建一个类

     public class TransactionUtils
    
    public static TransactionScope CreateTransactionScope()
    
    
        var transactionOptions = new TransactionOptions();
        transactionOptions.IsolationLevel = IsolationLevel.ReadCommitted;
        transactionOptions.Timeout = TransactionManager.DefaultTimeout;
        return new TransactionScope(TransactionScopeOption.Required, transactionOptions);
    
    
    

然后在代码中使用如下:

var newTransactionScope = TransactionUtils.CreateTransactionScope();

           try
            
                using (newTransactionScope)
                
                    using (var dbContextTransaction = db_context.Database.BeginTransaction(/*System.Data.IsolationLevel.ReadCommitted*/))
                    
                        try
                        
                            db_context.Database.CommandTimeout = 3600;

                            db_context.Database.SqlQuery<UpdateData>("UpdateProc @Param1, @Param2, @Param3, @Param4, @Param5, @Param6, @DateModified",
                                new SqlParameter("Param1", test1),
                                new SqlParameter("Param2", test2),
                                new SqlParameter("Param3", test3),
                                new SqlParameter("Param4", test4),
                                new SqlParameter("Param6", test5),
                                new SqlParameter("DateModified", DateTime.Now)).ToList();

                            dbContextTransaction.Commit();
                        
                        catch (TransactionAbortedException ex)
                        
                            dbContextTransaction.Rollback();
                            throw;
                        

关于问题 2(并发) 我找不到在 SQL Server 上的数据和我想从 SQLite 更新的数据(2 个不同的上下文)之间使用内置并发检查的方法

所以我将修改日期存储在 sql server 和 sqlite 中。 用户修改记录时更新sqlite日期修改, 同步运行时更新 sql server 上修改的日期。 在同步之前,我在 sqlServer 数据库中查询要更新的记录的修改日期,并将其与 if 语句中为该记录修改的 sqlite 的日期进行比较,然后为该记录运行更新存储过程或不运行

【讨论】:

以上是关于使用实体框架和存储过程进行并发检查的主要内容,如果未能解决你的问题,请参考以下文章

在实体框架中使用存储过程

使用实体框架核心生成和访问存储过程

实体框架与存储过程 - 性能度量

存储过程参数名称和实体框架

实体框架和 Oracle 客户端 - 存储过程问题

实体框架 - 您能否将导入的存储过程的结果类型映射到自定义实体类型?