如何在Date Entity Framework中回滚事务

时间:2014-02-03 13:06:00

标签: c# sql-server entity-framework

我正在尝试使用数据实体框架来创建我的数据访问层。在我迄今为止所做的工作中,我使用过ADO.Net。我试图了解EF中的交易如何运作。我已经阅读了负载,但它比我以前更加困惑我!我通常会做一些想法(比如简化):

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

现在我想在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!
            }
        }

根据我的阅读SaveChanges(false)表示将继续跟踪正在进行的更改。但是,如果出现问题,我该如何回滚交易呢?

2 个答案:

答案 0 :(得分:3)

TransactionScope中的回滚机制是隐含的。

基本上,如果您在Complete被处置之前未调用TransactionScope,它将自动回滚。请参阅Implementing an Implicit Transaction using Transaction Scope中的回滚交易部分。

从技术上讲,你甚至不需要在这里使用try...catch(除非你想执行其他一些操作,比如日志记录)。

答案 1 :(得分:3)

你不需要在catch块上做任何事情。只是不调用DbContext.SaveChanges,不会向数据库发送任何更改,一旦丢弃DbContext,它们就会丢失。

你确实遇到了问题。必须将DbContext包装在using块上,如下所示才能正确处理。顺便说一句,我认为不需要DbContext.SaveChanges(false);,您的代码应该只适用于最终DbContext.SaveChanges();。 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!
        }
    }