環境:Abp1.2 疑問:沒有調用工作單元的SaveChanges方法引起的事務提交時機的問題. 例如:有一個應用服務代碼如下: 根據用戶提交數據插入一條記錄,但在方法末未顯式調用SaveChanges方法 在Mvc的Controller里調用上述方法的代碼如下: 在_phraseAppServic ...
環境:Abp1.2
疑問:沒有調用工作單元的SaveChanges方法引起的事務提交時機的問題.
例如:有一個應用服務代碼如下:
public void CreatePhrase(PhraseCreateDto input) {var phrase = Mapper.Map<Phrase>(input); phrase.Id = Guid.NewGuid(); _phraseRepository.Insert(phrase); }
根據用戶提交數據插入一條記錄,但在方法末未顯式調用SaveChanges方法
在Mvc的Controller里調用上述方法的代碼如下:
[AbpAuthorize] public ActionResult Create() { ViewBag.Count = _phraseAppService.GetCount(); return View(); } [AbpAuthorize] [HttpPost] [ValidateInput(false)] public ActionResult Create(FormCollection fc) { CheckModelState(); if ((fc.Get("editorValue") != null) && (fc.Get("ChineseMean") != null)) { //ueditor有時會在最後多出一個br換行,需要去掉. var sentenceHtml = fc.Get("editorValue"); var phrase = new PhraseCreateDto { ChineseMean = fc.Get("ChineseMean"), SentenceHtml = sentenceHtml, //1.去掉Html標簽 2.把單引號,雙引號等被轉義的字元轉回來. Sentence = Server.HtmlDecode(Common.ReplaceHtmlMark(sentenceHtml)) }; _phraseAppService.CreatePhrase(phrase); } return Create(); }
在_phraseAppService.CreatePhrase(phrase),插入記錄之後,再調用無參的Create方法,在Create方法里ViewBag.Count = _phraseAppService.GetCount()得到的記錄數,仍然是原來的記錄數(並沒有+1),也就是說插入數據發生在獲取記錄數之後,如果在CreatePhrase方法末顯式調用當前工作單元的SaveChanges方法,每次就能獲得最新的記錄數:
public void CreatePhrase(PhraseCreateDto input) {var phrase = Mapper.Map<Phrase>(input); phrase.Id = Guid.NewGuid(); _phraseRepository.Insert(phrase); CurrentUnitOfWork.SaveChanges(); }
還有一點需要註意:工作單元與事務這二者的關係,假如有如下代碼:
public void CreatePhrase(PhraseCreateDto input) { using (var uow=UnitOfWorkManager.Begin()) { var phrase = Mapper.Map<Phrase>(input); phrase.Id = Guid.NewGuid(); _phraseRepository.Insert(phrase); uow.Complete(); } throw new Exception($"the exception inner {nameof(CreatePhrase)}"); }
在調用UnitOfWorkHanle的Complete之後,拋出一個異常,那麼有沒有插入數據呢?答案是不一定,因為在應用服務方法里預設的就是一個工作單元,再在方法裡面建一個更小範圍的工作單元,並不一定會創建一個事務,而有可能使用已經有的事務,而已有的事務歸外層的工作單元管理,所以調用Complete方法並不會提交事務,所以拋出異常後,外層的工作單元就會回滾事務.
不過Begin有幾個重載,例如:
Required:預設值,如果事務不存在則新建,如果已存在,則用之.
RequiresNew:始終新建事務.所以如果使用:var uow=UnitOfWorkManager.Begin(TransactionScopeOption.RequiresNew),則在拋出異常前提交事務.
Suppress:無需周圍事務上下文,工作單元域內的所有操作會被提交.