2012-03-08 39 views
11

我的表Sections(SQL Server)具有ID作为主键(int, identity)SortIndex列(int)用于排序目的。实体框架不更新由触发器修改的值

该数据库具有一个触发器,它在每个INSERT设置SortIndex := ID。显然,我想稍后更改排序索引,方法是交换两行的值。

我使用实体框架访问数据,全部使用MVC3 Web应用程序。

的问题是,当我插入一个新的对象插入到表实体框架不更新的SortIndex值。它也会缓存所有的数据,所以下面的调用从这个表中获取所有的对象也会给这个对象提供错误的SortIndex值。

我试图改变EDMXStoreGeneratedPattern此列。这似乎是伟大而优雅的,但并不能解决问题。

如果我设置为Identity,它会导致EF正确更新的价值,但它成为只读(试图改变时抛出的异常)。将其设置为Computed与此类似,但不会引发异常,而只是将值写入数据库。

我可以每次重新创建EF对象,如果我需要插入对象之后,再使用它,只是这样做:

DatabaseEntities db = new DatabaseEntities() 

但似乎丑陋的解决方法对我来说。

这个问题的解决方案是什么?

很明显,有些东西,不需要我在每个insert之后采取一些行动(并冒着被遗忘和不被注意的风险)是首选。

+0

可能重复:http://stackoverflow.com/questions/5445243/reload-field-value-modified-in-db-by-trigger-after-insert-update – 2012-03-08 10:14:04

+0

它很相似,但他似乎有一个他不需要写入的字段。 “计算”应该对他很好。它只是因为一些错误而不起作用。 – Arek 2012-03-08 12:51:09

回答

15

简而言之StoreGeneratedPattern表示该值由商店处理,您的应用程序将永远不会修改它。在这种情况下,您将在拨打SaveChanges后自动获得商店生成值。

如果您不使用StoreGeneratedPattern您将无法获得价值,您将不得不强制另一个查询执行来刷新您的实体。例如,你可以这样做:你需要通过触发器和应用更新这两个数据库中的值

objectContext.Refresh(RefreshMode.StoreWins, yourSection); 

一般情况下不与EF(以及可能还有其他ORM工具)扮演非常漂亮。

+0

感谢'Refresh'代码,它看起来比重新创建EF对象好。不幸的是,我不能赞成我的声誉。 – Arek 2012-03-09 09:29:33

+0

@Arek你可以接受答案 – 2012-03-09 09:41:11

+0

我知道我可以接受,但我正在测试一些其他可能的解决方案,所以还没有。 – Arek 2012-03-09 11:41:27

0

你知道你是否会在同一个请求中再次使用该列?

我会用每个请求的情况下,这通常让你出很多问题的情况下,因为一个新的EF上下文与每个请求创建的,所以你有一个新的数据每个请求一次。

由于长期存在的情况下,可能会增加死亡率,正如您所描述的。

无论如何,设置为计算的StoreGeneratedPattern应该是正确的。但只有在存储实际实体时才会自行更新。它没有通过插入或更新任何其他实体而得到更新。

http://msdn.microsoft.com/en-us/library/dd296755(v=vs.90).aspx

如果您创建一个新的实体或更改现有的实体,StoreGeneratedPattern属性设置为计算出的值是从服务器,当你在你的应用程序调用SaveChanges方法检索。 如果您将值分配给StoreGeneratedPattern属性设置为您的应用程序中的计算属性,则在调用SaveChanges方法时,该值将被服务器生成的值覆盖。

我们使用SQL的计算值选项排序GUID,它的工作确定。

+0

我在做什么是(1)添加新对象,(2)获取并返回SortIndex排序的所有对象以更新网页。所以是的,我在同一个请求中再次使用SortIndex。 – Arek 2012-03-08 10:43:10

+0

和StoreGeneratedPattert =计算 - 这似乎正确更新对象,但我无法修改SortIndex了。我尝试了,但是在我做了SaveChanges()之后,旧的值被恢复了。 EF似乎只是悄然忽略了这些变化。 – Arek 2012-03-08 10:45:11

+0

是的,storeGenerated明确表示它是在商店中生成的,所以它不会写它。 也许最适合你的方式是在保存之后设置entity.SortIndex = entity.id,然后你可以按照你的想法使用它。 – 2012-03-08 12:42:52

2

我发现'Ladislav Mrnka'的答案是确切的,并将其标记为已接受。以下是我尝试寻找某种解决方案时发现的其他解决方法。但是,我一直在寻找的解决方案通常是不可能的。

其中一种可能性是设置StoreGeneratedPattern = Computed让EF知道,这个值是计算出来的。然后,制定存储过程以实际更改SortIndex的值。通常它会更改两行中的值(交换它们),以更改排序顺序。此过程以及INSERT上的触发器可确保数据在数据库中保持一致。如果没有在SortIndex中设置适当的值,不可能创建新的行,但不能使两个对象具有相同的值(除非存储过程有错误),并且不可能以某种方式手动中断值,因为无法编辑通过EF。看起来像一个很好的解决方案。

很容易将存储过程映射到EF中的函数。

问题是,现在可以进入新行并正确更新缓存中的数据,但缓存在调用存储过程后未更新。还需要一些手动更新或刷新功能。否则,按照SortIndex排序的对象将得到错误的结果。

除此之外,可以为多个实体设置MergeOption = MergeOption.OverwriteChanges,这会导致EF更好地更新数据库中的数据。通过这样做,可以在插入对象或调用存储过程之后重新读取对象,并刷新它。但是,使用db.Section.OrderBy(o => o.SortIndex)读取对象集合仍然会返回排序顺序错误的缓存结果。

如果有人有兴趣,有可能使MergeOption默认到别的加入EF部分类,然后局部方法OnContextCreated,喜欢这里:

public partial class DatabaseEntities 
{ 
    partial void OnContextCreated() 
    { 
     Subsection.MergeOption = MergeOption.OverwriteChanges; 
     Section.MergeOption = MergeOption.OverwriteChanges; 
     Function.MergeOption = MergeOption.OverwriteChanges; 
    } 
} 
+0

谢谢,它适用于我! – Rodrigo 2015-06-12 12:32:22