2011-03-07 42 views
3

我使用实体框架4创建了一个非常简单的数据库。我希望能够在实体上使用事务,但似乎无法保持回滚的更改。我真的只需要一种方法来在实体保存到数据库之前放弃对实体的临时更改。如何使用实体框架对象上下文执行事务?

例如,以下代码使用实体框架对象上下文“MusicContainer”。在TransactionScope中,创建一个Artist实体。交易结束后没有完成;所以我期望事务被回滚。但是,程序运行起来就好像我从未创建过TransactionScope;在TransactionScope结束之后,线路music.SaveChanges()将对象保存到数据库。

class Program 
{ 
    static void Main(string[] args) 
    { 
     using (MusicContainer music = new MusicContainer()) 
     { 
      using (TransactionScope transaction = new TransactionScope()) 
      { 
       Artist artist = new Artist { Name = "Test" }; 
       music.Artists.AddObject(artist); 
      } 
      // The transaction ended without Complete(); shouldn't the changes be abandoned? 
      music.SaveChanges(); 
     } 
    } 
} 

如果实体框架不使用的TransactionScope,我期待它给来这里的路上,我怎么能得到我要找的功能?我有几种情况,一个函数的调用者在MusicContainer中传入,并且在我从函数返回之前,我需要将MusicContainer保持在一个干净的状态(即回滚更改,以便它们不会意外地被另一个SaveChanges调用在同一个MusicContainer对象上)。

回答

7

你并不需要一个TransactionScope在所有在这种情况下,SaveChanges()是所有的需要 - 如果你有其他using块与MusicContainer,这将是一个单独的事务,不会保存的任何变化您目前的using区块。 TransactionScope仅适用于跨越多个数据库上下文的事务。

一般情况下,上下文只能用于由相关操作组成的工作单元,一旦它们完成,请致电SaveChanges()。为每个单独的,不相关的工作单元开辟一个新的环境。话虽如此,只需在你的场景中使用这个:

​​
+0

您是否建议我为每笔交易使用单独的“使用(MusicContainer music = new MusicContainer())”?我的第一个怀疑是,如果我有几十个并行发生的话,这将是一个瓶颈 - 我错了吗? – 2011-03-07 17:22:57

+2

@notfed我相信开销很小 - 数据库连接仅在需要时由EF使用,即调用'SaveChanges()'或执行查询时,还可以查看此MSDN文章:http://msdn.microsoft.com/ en-us/library/cc853327.aspx – BrokenGlass 2011-03-07 17:42:44

+2

@notfed:您必须为每个事务使用新的容器。阅读这里:http://stackoverflow.com/questions/3653009/entity-framework-and-connection-pooling/3653392#3653392 – 2011-03-07 18:00:13

2

你有你的SaveChanges在错误的地方。

class Program 
{ 
    static void Main(string[] args) 
    { 
     using (MusicContainer music = new MusicContainer()) 
     { 
      using (TransactionScope transaction = new TransactionScope()) 
      { 
       Artist artist = new Artist { Name = "Test" }; 
       music.Artists.AddObject(artist); 
       music.SaveChanges(); 
      } 
      // The transaction ended without Complete(); the changes are abandoned? 
     } 
    } 
} 

如果交易失败,您不应该重复使用您的MusicContainer。为每个Unit of Work

+0

我有SaveChanges在故意的地方。我的观点是:在我给出的代码中,为什么SaveChanges保存这些更改? – 2011-03-07 17:16:30

+1

您必须在MusicContainer之前声明TransactionScope。 – edze 2011-03-07 17:24:43

0

实体框架的新人们应该能够使用TransactionScope的。如果需要仅通过此方法回滚所允许的更改,则需要启动新的TransactionScope。

using (MusicContainer music = new MusicContainer()) 
    { 
    using (TransactionScope transaction = new TransactionScope(TransactionScopeOptions.RequiresNew)) 
      { 
       Artist artist = new Artist { Name = "Test" }; 
       music.Artists.AddObject(artist); 
       music.SaveChanges(); 
       scope.Complete(); 
      } 
    } 
+0

好吧,如果我从一个调用者函数传递一个MusicContainer,我没有选择在TransactionScope中创建MusicContainer。 – 2011-03-07 17:18:42

+0

然后你不需要在你的方法中调用SaveChanges。让顶层函数调用SaveChanges – Amitabh 2011-03-07 17:22:17

+0

但是,我需要_abandon_对对象上下文所做的更改,我不希望调用方保存这些更改。 – 2011-03-07 17:24:37