2011-07-20 28 views
0

我想知道什么是执行下面的最好办法或做法:EF业务C#的MySQL连接器

我有一个名为EditUser方法,该方法具有以下定义:

public void EditUser(user user, Roles role) 
    { 
     using (TestEntities entities = new TestEntities()) 
     { 
      entities.Connection.Open(); 
      using (DbTransaction trans = entities.Connection.BeginTransaction()) 
      { 
       try 
       { 
        var tmpUser = entities.users.Where(fields => fields.UserId == user.UserId).FirstOrDefault(); 

        RoleManagement rm = new RoleManagement(); 
        string oldRole = tmpUser.roles.FirstOrDefault().Name; 
        string newRole = rm.GetRoleName(role); 

        if (oldRole == newRole) 
        { 
         entities.users.ApplyCurrentValues(user); 
        } 
        else 
        { 
         rm.UnbindRoles(tmpUser.UserId, entities.Connection); 
         this.DeleteUser(tmpUser.UserId, entities.Connection); 
         this.Register(user, role, entities.Connection); 
        } 

        entities.SaveChanges(); 
        trans.Commit(); 
       } 
       catch (Exception ex) 
       { 
        trans.Rollback(); 
        throw ex; 
       } 
      } 
     } 
    } 

正如你可能会注意到我调用了几种方法:UnbindRoles,DeleteUser和RegisterUser,它们都需要在同一事务下运行(EditUser运行的同一事务),以防万一发生故障时我需要回滚。

现在我的问题主要在这里...方法RegisterUser也启动一个新的事务,因为它添加一个用户并为新用户分配一个角色。

任何人都可以描述如何实现这个最好的方法吗?我试图用一个TransactionScope块,但因为我在运行中等信任环境

编辑

这个应用程序确认MySQL的.NET连接器供应商,因为我在中等信任使用的TransactionScope时有一个bug失败刚刚使用MS SQL Server数据库测试过相同的场景,并且其工作没有任何问题

+0

另一个话题: 糟糕!前投! 除非你真的想失去你的堆栈,否则你应该抛出。 – BennyM

+0

抛出被调用者捕获并再次抛出,以便Application_Error事件中的Global.asax将执行错误的通用处理 – Ryan

+0

只要确保知道throw之间的区别;并扔掉ex; – BennyM

回答

1

如果我的理解正确,您遇到的问题是您对DeleteUser和RegisterUser的调用正在启动新的事务并需要登录当前的事务。

几种方法来解决这个问题:

A)当你创建一个TransactionScope你可以说,他们只需要创建一个,如果没有一个已经可用。 B)不是采用第一种方法,而是引入私有方法,让我们说InnerEdit和InnerRegister包含逻辑,但不打开或关闭代码保留在公共可用编辑和注册方法中的任何事务。这些“内部”方法可以重用,而公共方法则包含基础设施。如果你打算在第二个方法为谷歌面向方面的编程,可以解决这些“横切关注点”

public void EditUser(user user, Roles role) 
{ 
    using (TestEntities entities = new TestEntities()) 
    { 
     entities.Connection.Open(); 
     using (DbTransaction trans = entities.Connection.BeginTransaction()) 
     { 
      InnerEditUser(entities, trans); 
      InnerThat(entities, trans); 
      InnerThis(entities,trans); 
      entities.SaveChanges(); 
      trans.Commit(); 
     } 
    } 
} 

TransactionScope options MSDN link

+0

我不确定你在哪里得到了userFromDb EntityObject下的ChangeRole方法,请你解释一下吗? – Ryan

+0

或者你创建的那些用户和角色类?然后,我会添加功能,以适应手头的问题。 – BennyM

+0

但问题是,在每个方法我保存更改(调用entities.SaveChanges()),因为有时我需要手动调用ChangeRole或AddUser方法(没有被EditUser或RegisterUser调用),这就是为什么我需要有一个事务,以便我可以提交或回滚取决于发生了什么 – Ryan

0

您可以注册检查现有事务并只创建一个(如果不存在)?这就是嵌套的TransactionScopes在类似情况下所能做到的。

+0

是的,这是一个选项,但我一开始就认为这个选项是某种“补丁工作” – Ryan

+0

这实际上是TransactionScope所做的 - 它在环境事务中使用,如果有的话,否则创建一个新事务。你只是自己做这件事,因为你不能使用TransactionScope。如果你用一种方法很好地包装它,这对我来说似乎是合法的。 – jlew