4

我有一个 UI 线程,它使用户能够设置实体的某些属性。

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

每个线程都有不同的内容是否安全,DbContexts并且只依赖于我的编程来始终避免修改相同的属性,然后尝试SaveChanges()在以不同方式修改相同实体的上下文上进行操作?

或者有没有一种更安全的方法来做到这一点,即程序员有可能在某一天更改代码,以便从两个不同的上下文安全地修改相同的属性?还是后一种情况只是程序员必须小心/重构的一种情况?

4

1 回答 1

2

理论部分

解决多线程环境下并发问题的三种方式:

  • 悲观的,这可以很容易地locks为正在编辑的项目完成 - 没有其他人可以编辑已经被编辑的项目。这是一种很难实现的方法,而且从性能的角度来看,这种方法也很糟糕——所有的编辑线程都在等待一个编写者,只是在浪费系统资源。
  • 乐观,这是解决问题的默认方法。主要思想是继续操作,直到成功为止。已经介绍了很多算法,我鼓励您阅读整个 wiki 文章,并且可能是一些额外的参考资料和/或有关主题的书籍。
  • semi-optimistic,这是一种混合方法,如果您需要lock一些操作,则使用这种方法,但不是全部。

练习部分

实体框架作者鼓励您在应用程序中使用乐观的方式。简单的用例是向模型添加RowVersion或类似名称的属性,并DBUpdatedExceptionUPDATE.

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

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

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

在此处输入图像描述

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

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

据我了解,您必须检查数据源的一些属性,所以我建议您阅读一篇关于此类用例的精彩文章(它是关于 MVC 应用程序的,但我相信您可以管理主要主意)。

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

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

如您所见,这种情况完全依赖于开发人员,您可以选择大量模式来自己解决并发问题。

于 2015-06-04T16:21:29.327 回答