thắc mắc Transaction trong EntityFramework

huycon1002

Senior Member
Mình đang có 1 api tạo báo giá dưới đây,mặc dù đã cho vào trong transaction rồi nhưng trong trường hợp function CreateDetails fail thì ko back lại những gì đã tạo trong function CreateQuotation mà vẫn lưu vào trong db.

Có cách nào để trong transaction call nhiều function,nếu 1 function lỗi thì back lại tất cả được không mọi ng?

C#:
        [HttpPost]
        [Route("CreateQuotation")]
        public async Task<IHttpActionResult> CreateQuotation(Quotation quo)
        {
            System.Data.Entity.DbContextTransaction transaction = db.Database.BeginTransaction();
            try
            {
                var id = await quo.CreateQuotation();
                quo.CreateDetails(id);
                transaction.Commit();
                return Ok("Tạo thành công");
            }
            catch(Exception ex)
            {
                transaction.Rollback();
                return Ok(ex);
            }
        }

C#:
public class Quotation
    {
        private PivotdataEntities db = new PivotdataEntities();
        public QUOTATION quotation { set; get; }
        public List<QUOTATION_DETAILS> details { set; get; }
        public async Task<int> CreateQuotation()
        {
            QUOTATION newq = new QUOTATION();
            newq = this.quotation;
            newq.CREATE_DATE = DateTime.Now;
            newq.QUOTATION_CODE = CreateQuotationCode("HN");
            db.QUOTATIONs.Add(newq);
            await db.SaveChangesAsync();
                
            return newq.ID;
        }

        public void CreateDetails(int id)
        {
            foreach (var item in this.details)
            {
                QUOTATION_DETAILS newdetail = new QUOTATION_DETAILS();
                newdetail = item;
                newdetail.QUOTATION_ID = id;
                db.QUOTATION_DETAILS.Add(newdetail);
                db.SaveChanges();
            }
        }

        public string CreateQuotationCode(string macongty)
        {
            string thamso = "";
            if (macongty == "HN")
            {
                thamso = "BGHN";
            }
            else
                if (macongty == "HCM")
            {
                thamso = "BGHCM";
            }
            Regex digitsOnly = new Regex(@"[^\d]");
            string year = DateTime.Now.Year.ToString().Substring(2, 2);
            string month = DateTime.Now.Month.ToString();
            string day = DateTime.Now.Day.ToString();
            if (month.Length == 1)
            {
                month = "0" + month;
            }
            if (day.Length == 1)
            {
                day = "0" + day;
            }

            string prefixNumber = thamso + year.ToString() + month.ToString() + day.ToString();
            string SoChungTu = (from quo in db.QUOTATIONs where quo.QUOTATION_CODE.Contains(prefixNumber) select quo.QUOTATION_CODE).Max();


            if (SoChungTu == null)
            {
                return thamso + year + month + day + "0001";
            }
            SoChungTu = SoChungTu.Substring(10, SoChungTu.Length - 10);
            string number = (Convert.ToInt32(digitsOnly.Replace(SoChungTu, "")) + 1).ToString();
            string result = number.ToString();
            int count = 4 - number.ToString().Length;
            for (int i = 0; i < count; i++)
            {
                result = "0" + result;
            }
            return thamso + year + month + day + result;
        }
    }
 
Mình ko rành về tech của framework này
Nhưng đọc sơ thì hiểu dc là nó đang chạy async (có thê mình sai)

Có thể sai ở tech khúc nào đó

Nếu ko tìm dc cách giải quyết (vụ tech) thì có thể tạo 1 biến Boolean ngoài khúc Try Catch
Mâc định là true . Nếu hàm nhảy vào Catch thì cho nó = false

Hết Try Catch thì check biến Bollean này
Nếu true thì chạy đạon Insert Detail


Code:
System.Data.Entity.DbContextTransaction transaction = db.Database.BeginTransaction();
            var id = null;
            Boolean aaa = true;
            try
            {
                id = await quo.CreateQuotation();
                
                transaction.Commit();
                return Ok("Tạo thành công");
            }
            catch(Exception ex)
            {
                aaa = false;
                transaction.Rollback();
                return Ok(ex);
            }
            
            If (aaa && id != null) {
                quo.CreateDetails(id);
            }
 
Mình ko rành về tech của framework này
Nhưng đọc sơ thì hiểu dc là nó đang chạy async (có thê mình sai)

Có thể sai ở tech khúc nào đó

Nếu ko tìm dc cách giải quyết (vụ tech) thì có thể tạo 1 biến Boolean ngoài khúc Try Catch
Mâc định là true . Nếu hàm nhảy vào Catch thì cho nó = false

Hết Try Catch thì check biến Bollean này
Nếu true thì chạy đạon Insert Detail


Code:
System.Data.Entity.DbContextTransaction transaction = db.Database.BeginTransaction();
            var id = null;
            Boolean aaa = true;
            try
            {
                id = await quo.CreateQuotation();
               
                transaction.Commit();
                return Ok("Tạo thành công");
            }
            catch(Exception ex)
            {
                aaa = false;
                transaction.Rollback();
                return Ok(ex);
            }
           
            If (aaa && id != null) {
                quo.CreateDetails(id);
            }
Nó vào catch nhưng ko rollback lại đc những gì đã thêm vào db trong cái CreateQuotation
 
vì biến dbEntities bạn new lại trong Quotation, và bạn lại tạo transaction trên 1 dbEntities instance khác chứ sao nữa.
Phải share chung 1 instance dbEntities thì mới làm transction dc chứ
 
ef của bạn là ef core cho .net core hay ef dùng cho .net framework.
nếu là ef core thì bạn tạo connection bằng cách đăng kí vào startup theo link https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-strings

rồi inject DbContext vào contructer bạn muốn chạy rồi theo link này để chạy transaction:
https://docs.microsoft.com/en-us/ef/core/saving/transactions

Vd kiểu kiểu thế này
C#:
private ApplicationDbContext _dbContext;

public UnitOfWork(ApplicationDbContext context)
{
   _dbContext = context;
}

public int CreateQuation(){
     using (var context1 = _dbContext.Database.BeginTransaction())
      {
             //handle transaction
      }
}
 
Nguyên tắc transaction là cùng connection. Ở đây bạn new một instance khác dbcontext rồi. Nên transacrion ko chạy dc
 
vì biến dbEntities bạn new lại trong Quotation, và bạn lại tạo transaction trên 1 dbEntities instance khác chứ sao nữa.
Phải share chung 1 instance dbEntities thì mới làm transction dc chứ

ef của bạn là ef core cho .net core hay ef dùng cho .net framework.
nếu là ef core thì bạn tạo connection bằng cách đăng kí vào startup theo link https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-strings

rồi inject DbContext vào contructer bạn muốn chạy rồi theo link này để chạy transaction:
https://docs.microsoft.com/en-us/ef/core/saving/transactions

Vd kiểu kiểu thế này
C#:
private ApplicationDbContext _dbContext;

public UnitOfWork(ApplicationDbContext context)
{
   _dbContext = context;
}

public int CreateQuation(){
     using (var context1 = _dbContext.Database.BeginTransaction())
      {
             //handle transaction
      }
}

Nguyên tắc transaction là cùng connection. Ở đây bạn new một instance khác dbcontext rồi. Nên transacrion ko chạy dc

inject qua constructor thôi chứ ai lại new dbContext thế

Thanks các fence,mình làm đc r nhé
 
Back
Top