简体   繁体   English

使用BeginTransaction()的实体框架

[英]Entity Framework using BeginTransaction()

I am trying to implement Entity Framework in my application and i should be able to commit and rollback the changes manually. 我试图在我的应用程序中实现实体框架,我应该能够手动提交和回滚更改。

First time when i execute the update statement it updates the table successfully and i am able to rollback the changes. 第一次执行update语句时,它成功更新了表,我可以回滚更改。 This is correct 这是对的

But second time when i execute the update statement, it updates the table successfully and also commits the changes. 但是第二次执行update语句时,它会成功更新表并提交更改。 So I am unable to rollback manually. 所以我无法手动回滚。 This is wrong 这是错的

Please let me know why it is happening and how to solve this issue. 请让我知道它为什么会发生以及如何解决这个问题。

The below code is just sample to reproduce my problem. 下面的代码只是重现我的问题的示例。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Common;
using System.Data;

namespace EFTest
{
    public class DBOperations
    {
        NorthwindEntities NorthwindContext;
        DbTransaction transObject;

        public DBOperations()
        {
        }

        public void ConnectDB()
        {
            try
            {
                if (NorthwindContext == null)
                {
                    NorthwindContext = new NorthwindEntities();
                    if (NorthwindContext != null && NorthwindContext.Connection.State != ConnectionState.Open)
                    {
                        NorthwindContext.Connection.Open();
                        transObject = NorthwindContext.Connection.BeginTransaction(IsolationLevel.ReadUncommitted);
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Database Error " + ex.Message);
            }
        }

        public int disconnect()
        {
            if (NorthwindContext != null && transObject != null)
            {
                try
                {
                    transObject.Rollback();
                }
                catch (Exception)
                {
                }
                transObject.Dispose();
                NorthwindContext.Connection.Close();
                NorthwindContext.Dispose();
            }

            return 0;
        }

        public void CommitTransaction()
        {
            if (NorthwindContext != null && transObject != null)
            {
                try
                {
                    transObject.Commit();
                }
                catch (Exception)
                {
                }
            }
        }

        public void RollbackTransaction()
        {
            if (NorthwindContext != null && transObject != null)
            {
                try
                {
                    transObject.Rollback();
                }
                catch (Exception)
                {
                }
            }
        }

        public int UpdateDB()
        {
            int _returnVal = 0;


            try
            {
                NorthwindContext.ExecuteStoreCommand("UPDATE Orders SET OrderDate = GETDATE() WHERE OrderID = '10248'");
            }
            catch (Exception ex)
            {
                throw new Exception("Database Error " + ex.Message);
            }

            return _returnVal;
        }
    }

    public class program
    {
        public program()
        {
            //Establishing the connection.
            DBOperations _DBOperations = new DBOperations();
            _DBOperations.ConnectDB();

            //Update the datebase
            _DBOperations.UpdateDB();                           //Update the database but it doesn't commit the changes.                       

            //Issue Rollback to rollback the transaction.
            _DBOperations.RollbackTransaction();                //Successfully Rollbacks the database changes.


            //Again Update the datebase
            _DBOperations.UpdateDB();                           //Update the database it commits the changes. 

            //Issue Rollback to rollback the transaction.
            _DBOperations.RollbackTransaction();                //Rollback fails.

        }
    }
}

You need to assign new transaction after commit or rollback of transaction . 您需要在提交或回滚事务后分配新事务。

public program()
{
    //Establishing the connection.
    DBOperations _DBOperations = new DBOperations();
    _DBOperations.ConnectDB();

    //Update the datebase
    _DBOperations.UpdateDB();    //Update the database but it doesn't commit the changes.

    //Issue Rollback to rollback the transaction.
    _DBOperations.RollbackTransaction();    //Successfully Rollbacks the database changes.

    _DBOperations.ConnectDB(); //you need to assign new transaction because your last 
                               //transaction is over when you commit or roll back 

    _DBOperations.UpdateDB();    //Update the database it commits the changes.

    //Issue Rollback to rollback the transaction.
    _DBOperations.RollbackTransaction();    //Rollback fails.
}

With TransactionScope Your DbOperations could look like this: 使用TransactionScope您的DbOperations可能如下所示:

public class DBOperations : IDisposable
{
    NorthwindEntities _context;
    private TransactionScope _transactionScope;

    public DBOperations()
    {
        this.Initialize();
    }

    private void Initialize()
    {
        try
        {
            this.Dispose();
            this._transactionScope = new TransactionScope();
            this._context = new NorthwindEntities();
            // no need to open connection. Let EF manage that.
        }
        catch (Exception ex)
        {
            throw new Exception("Database Error " + ex.Message);
        }
    }

    public void RollbackTransaction()
    {
            try
            {
                this._transactionScope.Dispose();
                this._transactionScope = null;
                this.Dispose();
                this.Initialize();
            }
            catch (Exception)
            {
                // TODO
            }
    }

    public int UpdateDB()
    {
        int _returnVal = 0;
        try
        {
            this._context.ExecuteStoreCommand("UPDATE Orders SET OrderDate = GETDATE() WHERE OrderID = '10248'");
        }
        catch (Exception ex)
        {
            throw new Exception("Database Error " + ex.Message);
        }
        return _returnVal;
    }

    public void Dispose()
    {
        if (this._transactionScope != null)
        {
            this._transactionScope.Complete();
            this._transactionScope.Dispose();
        }
        if (this._context != null) this._context.Dispose();
    }
}

And the program: 该计划:

public class program
{
    public program()
    {
        using (DBOperations dbOperations = new DBOperations())
        {
            dbOperations.UpdateDB(); // Update the database no commit.

            dbOperations.RollbackTransaction(); // Rollback.

            dbOperations.UpdateDB(); // Update the database no commit.

            dbOperations.RollbackTransaction(); // Rollback.
        } // Commit on Dispose.
    }
}

A connection that is opened within the scope of a TransactionScope automatically enlists in the transaction. 在TransactionScope范围内打开的连接会自动登记到事务中。 The transaction is only committed by calling Commplete() . 该事务通过调用Commplete()提交。 Disposing or unhandled exceptions will cause a rollback. 处置或未处理的异常将导致回滚。

If you do more than just a store command, as in changing objects and relying on the context's change tracking, you may to implement a retry mechanism in stead of just discarding the context and the changes. 如果您执行的不仅仅是存储命令,如更改对象和依赖于上下文的更改跟踪,您可以实现重试机制,而不是仅丢弃上下文和更改。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM