EF Transactions C# MySQL 连接器

发布于 2024-11-25 11:51:36 字数 1821 浏览 1 评论 0原文

我想知道实现以下内容的最佳方法或实践是什么:

我有一个名为 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 时存在错误,因为我刚刚测试过现在使用 MS SQL Server 数据库进行相同的场景,并且它可以正常工作

I was wondering what is the best way or practice to implement the following:

I have a method called EditUser which has the following definition:

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;
                }
            }
        }
    }

As you may notice I am calling several methods: UnbindRoles, DeleteUser and RegisterUser where all of them need to be running under the same transaction (the same transaction the EditUser is running) in case something fails I will need to rollback.

Now my problem is mostly here...the method RegisterUser also starts a new transaction since it adds a user and assign the new user a role.

Can anyone describe the best way how to implement this? I tried using a TransactionScope block but it fails since I am running this application in a Medium Trust environment

EDIT

Confirming that the MySQL .NET connector provider has a bug when using TransactionScope under Medium Trust since I have just tested now the same scenario using a MS SQL Server database and it works without any problems

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

与往事干杯 2024-12-02 11:51:36

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

解决此问题的几种方法:

A) 当您创建事务作用域时,您可以说,如果没有可用的事务作用域,则只需创建一个。

B)不采用第一种方法,而是引入私有方法,让我们假设 InnerEdit 和 InnerRegister 包含逻辑,但不打开或关闭代码保留在公开可用的 Edit 和 Register 方法中的任何事务。这些“内部”方法可以重用,而公共方法则包含基础设施。如果您要使用第二种方法谷歌进行面向方面的编程,则可以解决这些“横切问题”

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 选项 MSDN 链接

If I understand it correctly the problem you're having is that your calls to DeleteUser and RegisterUser are starting new transactions and need to enlist in the current one.

Several ways to fix this:

A) When you create a transactionscope you can say that they only need to create one if there isn't one already available.

B) Instead of doing the first approach introduce either private methods let's say InnerEdit and InnerRegister which contain the logic but don't open or close any transactions that code remains in the publicly available Edit and Register methods. Those "inner" methods can be reused while the public ones contain the infrastructure. If you're going the 2nd approach google for aspect oriented programming, that can address these 'cross cutting concerns'

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

把回忆走一遍 2024-12-02 11:51:36

您是否可以让 Register 检查现有交易,并仅在不存在时创建一个?这就是嵌套 TransactionScope 在类似情况下所做的事情。

Can you have Register check for an existing transaction and only create one if none exists? That is what nested TransactionScopes would do in similar circumstances.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文