我有一个 UI 线程,它使用户能够设置实体的某些属性。
我还有工作线程,它会自动修改实体的属性,重要的是,用户无权访问这些属性。
每个线程有不同的 DbContexts
并且只依赖于我的编程以始终避免修改相同的属性然后尝试在上下文中 SaveChanges()
是否安全哪个以不同的方式修改了相同的实体?
或者是否有更安全的方法来做到这一点,即程序员有可能在某一天更改代码,以便从两个不同的上下文中安全地修改相同的属性?或者后一种情况只是程序员必须小心/重构的情况?
最佳答案
理论部分
有three ways to resolve the concurrency issues在多线程环境中:
- 悲观,这可以通过对正在编辑的项目使用
locks
轻松完成 - 没有其他人可以编辑已经被编辑的项目。这种方法很难实现,而且从性能角度来看这种方法很糟糕 - 所有编辑线程都在等待单个编写器,只是在浪费系统资源。 - 乐观,这是解决问题的默认方式。主要思想是您继续操作直到成功。已经介绍了很多算法,我鼓励您阅读整个 wiki 文章,可能还有一些 additional references和/或主题书籍。
- 半乐观,这是一种混合方法,如果您需要
锁定
某些操作,但不是全部,则使用这种方法。
练习部分
Entity Framework 作者鼓励您在您的应用中使用乐观的方式。 The simple use-case是向您的模型添加 RowVersion
或类似名称的属性,并在 UPDATE
期间捕获 DBUpdatedException
。
您可以使用 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");
}
}
据我了解,您必须检查数据源的某些属性,因此我建议您阅读 a great article regarding such use-cases (它是关于 MVC 应用程序的,但我相信您可以掌握主要思想)。
您还可以在 MSDN 上找到有关 Entity Framework 中并发性的几篇文章:
- Optimistic Concurrency Patterns
- 使用 Reload 解决乐观并发异常(数据库胜出)
- 在客户端获胜时解决乐观并发异常
- 乐观并发异常的自定义解决
- 使用对象自定义解决乐观并发异常
- Working with Property Values
- 获取和设置单个属性的当前值或原始值
- 获取和设置未映射属性的当前值
- 检查属性是否标记为已修改
- 将属性标记为已修改
- 读取实体所有属性的当前值、原始值和数据库值
- 设置来自另一个对象的当前值或原始值
- 设置字典中的当前值或原始值
- 使用 Property 从字典中设置当前值或原始值
- 创建包含当前值、原始值或数据库值的克隆对象
- 获取和设置复杂属性的当前值或原始值
- 使用
DbPropertyValues
访问复杂属性
如您所见,这种情况完全依赖于开发人员方面,您可以选择大量模式来自行解决并发问题。
关于c# - 从多个线程修改 Entity Framework 实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30641198/