在查询时使用databasevalue更新附加实体的属性

时间:2012-11-01 08:26:48

标签: .net entity-framework optimistic-concurrency

我有一个实体类,它有一个整数属性(名为ROW_VERSION),ConcurrencyMode设置为“Fixed”,用于乐观并发检查。在保存此类型的实体之前,我在应用程序代码中增加此列的值(因此StoreGeneratedPattern设置为None)。这在保存更改时效果很好。

现在,当我有一个先前加载的实体(使用ROW_VERSION = x)并且我创建一个新的DbContext时,我还想检测并发错误,附加此实体并发出涉及该实体的查询。问题在于,如果ROW_VERSION由另一个客户端应用程序(ROW_VERSION = x + 1)递增,则在我的查询期间不会检测到这一点,因为附加实体的值具有明显优先级(这对于常见列值完全有意义) )。

另一方面,对于我的并发检查列,如果EF使用当前数据库值更新值,那将是很好的,因此我可以将其与期望值进行比较。或者,从查询执行中抛出的异常也是可以接受的。

我正在使用.NET 4.0的实体框架。

编辑(回应Gert Arnold的评论):

我试着再澄清一下我的问题......

我的申请一般如何运作的说明:

  • 有一个树视图显示我的可用实体对象,在选择一个实体对象时,从DB加载完整实体以显示在详细视图中,可在其中进行编辑

  • 对实体对象的修改不会立即保存,而是缓存在内存中,因此当用户点击保存按钮时,不同实体对象的修改会堆积起来并一起保存。

  • DbContexts是为查询和保存更改单独创建的(即我没有始终使用相同的DbContext,但它们会根据需要进行实例化。)

  • 当加载实体对象以在详细视图中显示时,所有先前修改的实体对象(已缓存)将首先附加到用于查询的DbContext。然后发出实际查询。 因此,如果我查询实体对象,那么在我将修改后的版本作为结果而不是数据库中的版本(在此期间可能已更改)之前进行了修改。

所以这是一个显示我的问题的例子:

  1. Client App 1加载一个ROW_VERSION = 1的实体对象,处理DbContext并保留对该实体对象的引用以供进一步编辑。

  2. Client App 2加载步骤1中提到的同一实体对象,更改属性并保存更改。这会导致DB中的ROW_VERSION递增(现在为2)。

  3. Client App 1的用户现在更改了实体对象的某些属性(它仍在内存中,ROW_VERSION为1)。

  4. 在客户端应用程序1保存更改之前,它会加载一些其他实体对象以供显示,并最终再次选择有问题的实体对象(例如,查看所做的更改)。这会导致查询结果将包含已更改的实体对象(因为它在将实际查询发送到数据库之前附加到DbContext)。

    这是我的问题:此时实体框架可以将附加对象的ROW_VERSION与实际查询结果中的对象的ROW_VERSION进行比较,检测不匹配,例如抛出异常。

    但是EF会像所有其他属性一样处理ROW_VERSION属性,而这些属性可能已被客户端更改。

  5. 所以我希望EF专门处理ROW_VERSION属性,并在每个查询上比较它的值以检测其他客户端的更改。这样,我会比等待SaveChanges调用时更早地检测到并发情况。

1 个答案:

答案 0 :(得分:1)

我想我现在明白了,但我不知道实体框架如何在这里帮助你。

  1. 每个定义的乐观并发是一种在提交数据时处理冲突的策略。不是在读数据时。因此,如果ConcurrencyMode以这种方式实现(即使在可配置的情况下),这将偏离预期的行为。
  2. 假设EF实体类可以配置为在读取时表现如此。在检索这些实体的列表或包含这些实体的对象图时,处理所有可能的异常将非常困难。整个阅读应该回滚吗?因此,它可能仅在读取单个实体对象时才有用。这将是一个非常(读取:太)细粒度的配置规范。
  3. 据我所知,如果你想要这个早期预警系统,你必须自己编程。这应该涉及一些查询来具体读取版本值,因为带有Refresh(ObjectContext)或StoreWins(DbContext)的Reload总是会覆盖所有值。