从多个线程修改实体框架实体

时间:2015-06-04 10:19:40

标签: c# multithreading entity-framework concurrency database-concurrency

我有一个UI线程,可以让用户设置实体的某些属性。

我还有工作线程,它会自动修改实体的属性,重要的是,用户无权访问。

每个线程有不同的DbContexts是否安全并且仅依赖于我的编程以始终避免修改相同的属性,然后尝试在具有相同实体修改的上下文中SaveChanges()方式?

或者是否有更安全的方法来实现这一点,即程序员有朝一日可以更改代码以便安全地从两个不同的上下文修改相同属性的方式?或者后一种情况只是程序员必须小心/重构的情况?

1 个答案:

答案 0 :(得分:2)

理论部分

多线程环境中有three ways to resolve the concurrency issues

  • 悲观,对于正在编辑的项目,可以使用locks轻松完成此操作 - 没有其他人可以编辑已编辑的项目。这是非常难以实现的方法,这种方式在性能视图中非常糟糕 - 所有编辑线程都在等待单个编写器,并且只是浪费系统资源。
  • 乐观,这是解决问题的默认方式。主要的想法是你继续操作直到你成功。已经介绍了很多算法,我鼓励你阅读整篇wiki文章,可能是一些additional references和/或关于主题的书籍。
  • 半乐观,这是一种混合方法,如果您需要lock某些操作,而不是全部操作,则会使用这种方式。

练习部分

实体框架作者鼓励您在应用中使用乐观的方式。 The simple use-case是将RowVersion或类似名称的属性添加到模型中,并在DBUpdatedException期间捕获UPDATE

您可以使用Code-First解决方案,如下所示:

[Timestamp]
public byte[] RowVersion { get; set; }

Database-First解决方案(使用数据库编辑器添加列):

enter image description here

之后,您的简单案例代码将如下:

using (var context = new SchoolDBEntities())
{
    try
    {
        context.Entry(student1WithUser2).State = EntityState.Modified;
        context.SaveChanges();
    }
    catch (DbUpdateConcurrencyException ex)
    {
        Console.WriteLine("Optimistic Concurrency exception occured");
    }
}

据我所知,您必须检查数据源的某些属性,因此我建议您阅读a great article regarding such use-cases(它是关于MVC应用程序,但我确信您可以管理主要主意)。

您还可以在MSDN上的Entity Framework中找到几篇关于并发性的文章:

  • Optimistic Concurrency Patterns
    • 使用Reload(数据库获胜)解决乐观并发异常
    • 在客户获胜时解决乐观并发异常
    • 自定义解决乐观并发异常
    • 使用对象自定义解决乐观并发异常
  • Working with Property Values
    • 获取和设置单个属性的当前值或原始值
    • 获取和设置未映射属性的当前值
    • 检查属性是否标记为已修改
    • 将属性标记为已修改
    • 读取实体所有属性的当前值,原始值和数据库值
    • 从另一个对象设置当前值或原始值
    • 从字典中设置当前值或原始值
    • 使用Property
    • 设置字典中的当前值或原始值
    • 创建包含当前,原始或数据库值的克隆对象
    • 获取和设置复杂属性的当前值或原始值
    • 使用DbPropertyValues访问复杂属性

正如您所看到的,这种情况完全依赖于开发人员方面,并且您可以选择大量模式来自行解决并发问题。