【发布时间】:2010-12-06 12:53:49
【问题描述】:
我有一个 WCF 服务正在调用我的 Entity Framework Repository 类来访问数据。我正在使用 Entity Framework 4 CTP,并且正在使用我自己的 POCO 对象而不是自动生成的实体对象。
上下文生命周期仅限于方法调用。对于 Select/Insert 和 Update 方法,我创建上下文并在返回断开连接的实体对象的同一方法中处理它。
我现在正在尝试找出处理并发问题的最佳方法。例如,这就是我的更新方法的样子
public static Sale Update(Sale sale)
{
using (var ctx = new DBContext())
{
var SaleToUpdate =
(from t in ctx.Sales where t.ID == sale.ID select t).FirstOrDefault();
if (SaleToUpdate == null) throw new EntityNotFoundException();
ctx.Sales.ApplyCurrentValues(sale);
ctx.SaveChanges();
return sale;
}
}
这很好用,但是因为我以断开连接的方式工作,所以如果在您拾取记录后已修改记录,则不会引发异常。这会导致并发问题。
当您在 WCF 上使用实体框架并且不保留全局上下文时,解决此问题的最佳方法是什么?
我能想到的唯一方法是给我的对象一个版本号,并在每次调用 save 时递增它。然后,这将允许我在保存之前检查版本是否更改。这不是我所知道的最简洁的解决方案,并且仍然允许客户更改他们的版本号,我真的不希望他们能够这样做。
编辑: 使用 Ladislav Mrnka 对我的实体中的 RowVersion 字段的建议,我的每个实体现在都有一个名为 RowVersion 类型的版本的字段。然后我将我的 Update 方法更改为如下所示。
public static Sale Update(Sale sale)
{
using (var ctx = new DBContext())
{
var SaleToUpdate =
(from t in ctx.Sales where t.ID == sale.ID select t).FirstOrDefault();
if (SaleToUpdate == null) throw new EntityNotFoundException();
if (!sale.Version.SequenceEqual(SaleToUpdate .Version))
throw new OptimisticConcurrencyException("Record is out of date");
ctx.Sales.ApplyCurrentValues(sale);
ctx.SaveChanges();
return sale;
}
}
它似乎有效,但如果我应该以不同的方式做,请告诉我。我尝试通过将版本字段并发模式设置为固定来使用内置于并发控制的实体框架,不幸的是,当我执行查询以获取未更改的 SaleToUpdate 时,这不起作用,它选择了它的版本并使用它来进行并发检查这显然是当前的。感觉实体框架可能在这里遗漏了一些东西。
【问题讨论】:
-
在 NHibernate 中,您可以将其配置为使用时间戳字段来了解数据是否已更改。我对 EF 感到非常沮丧,以至于我现在已经切换到 NHibernate - 尽管我从未尝试过 EF4.0 CTP 的东西。
-
这对我来说似乎不对。您不应该读取这些值,然后将其保存。在您读取和保存之间,值可能会发生变化,尽管变化很小,但可能会。最好用你的值保存,如果 rowversion 发生变化则捕获异常。 EF 会为您检查,因为它的并发类型是固定的。或者将读取和保存更改封装在事务中。 EF 将在您保存时开始事务,但不会更早(读取)。
-
@Gavin:就像 MarcelDevG 正确提到的那样,您不需要(也不应该)手动检查行版本。只需使用我在答案中显示的 TimestampAttribute 就可以了。当然,如果您愿意,您可以尝试将 SaveChanges 包装起来并捕获 OptimisticConcurrencyException。
-
内置并发异常永远不会被抛出,因为我首先从数据库中获取对象,然后附加更改它保留了新检索到的数据库记录中的版本
-
好的,我想我们在这里跑题了,但是您可以将您的 POCO 附加到上下文中,然后调用 ChangeObjectState 将状态更改为修改 然后 SaveChanges()。顺便说一句,这是一个重要的话题,值得提出自己的问题。
标签: wcf entity-framework concurrency