我正在尝试使用数据实体框架来创建我的数据访问层。在我迄今为止所做的工作中,我使用过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)
表示将继续跟踪正在进行的更改。但是,如果出现问题,我该如何回滚交易呢?
答案 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!
}
}