如何使用Entity Framework对象上下文执行事务?

3

我使用Entity Framework 4创建了一个非常简单的数据库。我想要能够在实体上使用事务,但似乎无法阻止更改回滚。 我只需要一种在将实体保存到数据库之前放弃临时更改的方法。

例如,以下代码使用了一个Entity Framework对象上下文"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保持在干净状态(即回滚更改,以便它们不会意外地保存在同一MusicContainer对象上调用的另一个SaveChanges中)。
3个回答

7
在这种情况下,您根本不需要使用TransactionScope,只需要使用SaveChanges()即可 - 如果您有另一个using块与MusicContainer一起使用,则它将在单独的事务中,并且不会保存当前using块内所做的任何更改。只有涉及跨多个DB上下文的事务时才需要使用TransactionScope
通常,上下文应仅用于相关操作的工作单元,在完成它们后调用SaveChanges()。对于每个单独的、无关的工作单元,打开一个新的上下文。话虽如此,在您的情况下只需使用以下内容:
        using (MusicContainer music = new MusicContainer())
        {
                Artist artist = new Artist { Name = "Test" };
                music.Artists.AddObject(artist);
                music.SaveChanges();
        }

你是在建议我为每个事务使用单独的“using (MusicContainer music = new MusicContainer())”吗?我的第一个怀疑是,如果我有数十个这样的并行事务,这将成为瓶颈 - 我的想法是错误的吗? - Jay Sullivan
2
@notfed 我相信开销很小 - EF 仅在需要时才使用 DB 连接,即在调用 SaveChanges() 或执行查询时,还请查看此 MSDN 文章:http://msdn.microsoft.com/en-us/library/cc853327.aspx - BrokenGlass
2
@notfed:每次交易都必须使用新容器。请阅读这里:https://dev59.com/oHA65IYBdhLWcg3wvxaE#3653392 - Ladislav Mrnka
谢谢,伙计们。我知道我在处理这个问题的某些方面上有些错误的角度,而这帮助我重新理清了思路。 - Jay Sullivan

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。为每个工作单元创建一个新的容器。


我故意将SaveChanges放错位置。我的观点是:在我提供的代码中,为什么SaveChanges会保存这些更改? - Jay Sullivan
1
你必须在MusicContainer之前声明TransactionScope。 - edze

0

Entity Framework 应该能够使用 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(); 
          }
    }

如果调用函数传递给我一个MusicContainer,我就没有在TransactionScope内创建MusicContainer的选项。 - Jay Sullivan
那么你的方法中就不需要调用SaveChanges。让顶层函数调用SaveChanges即可。 - Amitabh
但是,我需要放弃对对象上下文所做的更改,并且我不希望调用者保存这些更改。 - Jay Sullivan
非常感谢你的帮助,但还是不行 :/。正如其他答案所指出的那样,我认为我应该真正地将容器本身作为我的交易对象。 - Jay Sullivan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接