我有一个UI线程,使用户可以设置实体的某些属性.
我还有工作线程,它会自动修改实体的属性,重要的是,用户无权访问.
在每个线程中使用不同的DbContexts是否安全并且只依赖于我的编程总是避免修改相同的属性然后尝试在具有以不同方式修改相同实体的上下文中的SaveChanges()?
或者是否有一种更安全的方法,即程序员有朝一日可以更改代码,以便安全地从两个不同的上下文修改相同的属性?或者后一种情况只是程序员必须小心/重构的情况?
最佳答案 理论部分
多线程环境中有three ways to resolve the concurrency issues:
>悲观,这可以通过锁定正在编辑的项目轻松完成 – 没有其他人可以编辑已经编辑的项目.这是非常难以实现的方法,这种方式在性能视图中非常糟糕 – 所有编辑线程都在等待单个编写器,并且只是浪费系统资源.
>乐观,这是解决问题的默认方式.主要的想法是你继续操作直到你成功.已经介绍了很多算法,我鼓励你阅读整篇wiki文章,可能是一些additional references和/或关于主题的书籍.
>半乐观,这是一种混合方法,如果您需要锁定某些操作,则会使用这种方式,但不是全部.
练习部分
实体框架作者鼓励您在应用中使用乐观的方式. 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访问复杂属性
正如您所看到的,这种情况完全依赖于开发人员方面,并且您可以选择大量模式来自行解决并发问题.