简体   繁体   English

如何在Date Entity Framework中回滚事务

[英]How to rollback a transaction in Date Entity Framework

I am trying to use the Data Entity Framework to create my Data Access Layer. 我正在尝试使用数据实体框架创建我的数据访问层。 In the work I have done up to now I have used ADO.Net. 在到目前为止的工作中,我使用了ADO.Net。 I am trying to get my head around how transactions work in EF. 我正在努力弄清事务在EF中的工作方式。 I ave read loads but its all confussed me even more than I was before!! 我读了很多书,但是它比以前让我更加困惑! I would usually do somethink like (simplified for example): 我通常会做一些思考(例如简化):

using (SqlConnection conn = new SqlConnection(_connString))
{
    using (SqlTransaction trans = conn.BeginTransaction())
    {
        try
        {
            using (SqlCommand cmd = new SqlCommand("usp_CreateNewInvoice", conn))
            {
                cmd.Transaction = trans;
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.Parameters.Add(new SqlParameter("@InvoiceName", Invoice.invoicename));
                 cmd.Parameters.Add(new SqlParameter("@InvoiceAddess", Invoice.invoiceaddress));
                 _invoiceid = Convert.ToInt32(cmd.ExecuteScalar());
            }
            foreach (InvoiceLine inLine in Invoice.Lines)
            {
                using (SqlCommand cmd = new SqlCommand("usp_InsertInvoiceLines", conn))
                {
                    cmd.Transaction = trans;
                    cmd.CommandType = CommandType.StoredProcedure;
                    cmd.Parameters.Add(new SqlParameter("@InvNo", _invoiceid));
                    cmd.Parameters.Add(new SqlParameter("@InvLineQty", inLine.lineqty));
                    cmd.Parameters.Add(new SqlParameter("@InvLineGrossPrice", inLine.linegrossprice));
                    cmd.ExecuteNonQuery();
                }
            }
            trans.Commit();
        }
        catch (SqlException sqlError)
        {
            trans.Rollback();
        }
    }
}

Now I want to do the same in EF: 现在我想在EF中做同样的事情:

        using (TransactionScope scope = new TransactionScope())
        {
            try
            {
                var DbContext = new CCTStoreEntities();

                CCTInvoice invHead = new CCTInvoice();
                invHead.Name = Invoice.invoicename;
                invHead.Address = Invoice.invoiceaddress;

                DbContext.CCTInvoices.Add(invHead);
                DbContext.SaveChanges(false);
                _iid = invHead.InvoiceId;

                foreach (InvoiceLine inLine in Invoice.Lines)
                {
                    CCTInvoiceLine invLine = new CCTInvoiceLine();
                    invLine.InvoiceNo = _iid;
                    invLine.Quantity = inLine.lineqty;
                    invLine.GrossPrice = inLine.linegrossprice;
                    DbContext.CCTInvoiceLines.Add(invHead);
                    DbContext.SaveChanges(false);
                }

                DbContext.SaveChanges();
                scope.Complete();

            }
            catch
            {
                //Something went wrong
                //Rollback!
            }
        }

From what I read SaveChanges(false) means the changes being made will continue to be tracked. 从我读到的SaveChanges(false)表示将继续跟踪所做的更改。 But how do I rollback the transaction if something goes wrong? 但是,如果出现问题,我该如何回滚事务?

The rollback mechanism in a TransactionScope is implicit. TransactionScope的回滚机制是隐式的。

Basically, if you don't call Complete before the TransactionScope gets disposed it will automatically rollback. 基本上,如果在TransactionScope之前不调用Complete ,它将自动回滚。 See the Rolling back a transaction section in Implementing an Implicit Transaction using Transaction Scope . 请参阅“ 使用事务范围实现隐式事务”中“回滚事务”部分。

So technically, you don't even need to use a try...catch here (unless you want to perform some other action like logging). 因此,从技术上讲,您甚至不需要在此处使用try...catch (除非您想执行其他操作,例如记录日志)。

You don't need to do anything on your catch block. 您无需在catch块上执行任何操作。 Just by not calling DbContext.SaveChanges no changes will be sent to the database, and they will be lost once DbContext is disposed. 只需不调用DbContext.SaveChanges ,就不DbContext.SaveChanges任何更改发送到数据库,并且一旦处理DbContext,更改将丢失。

You do have a problem though. 你确实有问题。 DbContext must be wrapped on a using block as follows to be properly disposed. 必须正确地将DbContext包装在using块上,如下所示。 BTW, I don't think DbContext.SaveChanges(false); 顺便说一句,我不认为DbContext.SaveChanges(false); is needed, your code should work with just the final DbContext.SaveChanges(); 需要时,您的代码应仅与最终的DbContext.SaveChanges(); . EF will take care of wiring up all your Foreign Keys, so you don't need to do that explicitly. EF将负责连接所有外键,因此您无需明确地进行此操作。

    using (TransactionScope scope = new TransactionScope())
    {
        try
        {
            using (var DbContext = new CCTStoreEntities())
            {
                CCTInvoice invHead = new CCTInvoice();
                invHead.Name = Invoice.invoicename;
                invHead.Address = Invoice.invoiceaddress;

                DbContext.CCTInvoices.Add(invHead);
                DbContext.SaveChanges(false); // This is not needed
                _iid = invHead.InvoiceId;     // This is not needed

                foreach (InvoiceLine inLine in Invoice.Lines)
                {
                    CCTInvoiceLine invLine = new CCTInvoiceLine();
                    invLine.InvoiceNo = _iid; // This is not needed
                    invLine.Quantity = inLine.lineqty;
                    invLine.GrossPrice = inLine.linegrossprice;
                    DbContext.CCTInvoiceLines.Add(invHead);
                    DbContext.SaveChanges(false); // This is not needed
                }

                DbContext.SaveChanges();
                scope.Complete();
            }
        }
        catch
        {
            //Something went wrong
            //Rollback!
        }
    }

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

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