Entity Framework - 12. Transactions

[ 2009-04-02 09:23:27 | 作者: yuhen ]
字号: | |
EF 默认会实现一个隐式事务,注意看 ObjectContext.SaveChanges()。
public class ObjectContext : IDisposable
{
    public int SaveChanges(bool acceptChangesDuringSave)
    {
        ...

        using (DbTransaction transaction = null)
        {
            if (flag2)
            {
                transaction = connection.BeginTransaction();
            }

            objectStateEntriesCount = this._adapter.Update(this.ObjectStateManager);
            
            if (transaction != null)
            {
                transaction.Commit();
            }
        }
        
        ...
    
    }
}

当我们没有显式提供事务时,SaveChanges() 通过 Connection.BeginTransaction() 启动事务。我们用一个例子测试一下。
using (var context = new TestEntities())
{
    context.AddToUsers(new User { Name = "userx", Age = 27 });

    var user = context.Users.First(u => u.Name == "user1");
    user.Age += 1;

    // Make OptimisticConcurrencyException
    using (var context2 = new TestEntities())
    {
        var user2 = context2.Users.First(u => u.Name == "user1");
        user2.Age += 3;
        context2.SaveChanges();
    }

    try
    {
        context.SaveChanges();
    }
    catch (OptimisticConcurrencyException ex)
    {
        Console.WriteLine("OptimisticConcurrencyException");
    }

    Console.WriteLine(context.Users.Count(u => u.Name == "userx"));
}

输出:
OptimisticConcurrencyException
0

在上面这个例子中,我们人为制造了一个并发异常,但你会发现 AddToUsers() 同样没有成功,显示是 SaveChanges() 中事务起了作用。当然这个隐式事务范围也仅限于 SaveChanges() 内部,也就是说如果我们在 AddToUser() 后立即调用 SaveChanges(),那么是可以成功创建 "userx" 的。
using (var context = new TestEntities())
{
    context.AddToUsers(new User { Name = "userx", Age = 27 });
    context.SaveChanges();

    var user = context.Users.First(u => u.Name == "user1");
    user.Age += 1;

    // Make OptimisticConcurrencyException
    using (var context2 = new TestEntities())
    {
        var user2 = context2.Users.First(u => u.Name == "user1");
        user2.Age += 3;
        context2.SaveChanges();
    }

    try
    {
        context.SaveChanges();
    }
    catch (OptimisticConcurrencyException ex)
    {
        Console.WriteLine("OptimisticConcurrencyException");
    }

    Console.WriteLine(context.Users.Count(u => u.Name == "userx"));
}

输出:
OptimisticConcurrencyException
1

我们可以显式启动一个事务,这样即便多次调用 SaveChanges() 也在同一个事务范围内。
using (var context = new TestEntities())
{
    context.Connection.Open();
    var trans = context.Connection.BeginTransaction();

    try
    {
        context.AddToUsers(new User { Name = "userx", Age = 27 });
        context.SaveChanges();

        var user = context.Users.First(u => u.Name == "user1");
        user.Age += 1;

        // Make OptimisticConcurrencyException
        using (var context2 = new TestEntities())
        {
            var user2 = context2.Users.First(u => u.Name == "user1");
            user2.Age += 3;
            context2.SaveChanges();
        }

        context.SaveChanges();
        trans.Commit();
    }
    catch
    {
        Console.WriteLine("Transaction Roolback!");
        trans.Rollback();
    }

    Console.WriteLine(context.Users.Count(u => u.Name == "userx"));
}

输出:
Transaction Roolback!
0

这回虽然还是多次调用 SaveChanges(),但依然无法添加 "userx",显然这种显示事务生效了。当然,我们还可以用 TransactionScope 启动分布式事务。
using (var trans = new TransactionScope())
{
    try
    {
        using (var context = new TestEntities())
        {
            context.AddToUsers(new User { Name = "userx", Age = 27 });
            context.SaveChanges();
        }

        using (var context2 = new TestEntities())
        {
            var user = context2.Users.First(u => u.Name == "user1");
            user.Age += 1;

            // Make OptimisticConcurrencyException
            using (var context3 = new TestEntities())
            {
                var user2 = context3.Users.First(u => u.Name == "user1");
                user2.Age += 3;
                context3.SaveChanges();
            }

            context2.SaveChanges();
        }

        trans.Complete();
    }
    catch
    {
        Console.WriteLine("Exception!");
    }
}
[最后修改由 yuhen, 于 2009-04-02 09:24:20]
评论Feed 评论Feed: http://www.rainsts.net/feed.asp?q=comment&id=800

这篇日志没有评论。

发表评论
表情图标
[smile] [confused] [cool] [cry]
[eek] [angry] [wink] [sweat]
[lol] [stun] [razz] [redface]
[rolleyes] [sad] [yes] [no]
[heart] [star] [music] [idea]
UBB代码
转换链接
表情图标
悄悄话
用户名:   密码:  
验证码 * 请输入验证码