Asp.Net Mvc Eş zamanlı (DbConcurrency) Güncelleme Kontrolü
Selamlar uzun zamandır yazı yazmaya vaktim olmadığı için bugün uzun bir sürenin ardından bir şeyler yazmak istedim bugünkü konumuz Entity Framework’de olan eş zamanlı güncelleme kontrolünü sizlere anlatacağım birden fazla kişini aynı form üzerinde çalışması durumunda kullanacağımız yöntem ile sorunsuz çalışan bir sistem kurgulayabilirsiniz.
Öncelikle Eş zamanlı (DbConcurrency) Güncelleme Nedir ?
Asp.Net.Mvc’de bildiginiz üzere update senaryosunda bir id ye query string üzerinden get atılır model dolup view’da da html’i render ederek kullancıya gösterir. Bu querystring’i tarayıcıya yapıştırdığınızda sayfa yüklü olarak gelecektir siz bu sayfayı 4-5 farklı sekmede açarsanız her seferinde dbye gidip kaydın son halini getirecek şekilde çalışacak ve kullanıcı her seferinde kaydı güncelleyecek ama diğer sekmelerdeki kayıtlar hep eski kalacak ve siz post ettiğiniz anda hep eski haline dönmüş olacak ve çok mantıklı olmayacak Örnek olarak IK modülünde bir değişiklik yapılacak ve bu değişiklik 2 kişiye aynı anda haber verildi aynı anda güncelleme başlıyorlar birisi önce kaydete bastı diğeri sonra ilk basan kazanıp kaydı güncelleyecek ikinci basan kişiye validation vererek güncelletmeyerek olayı çözüyor olacağız.
Eş zamanlı (DbConcurrency) Nasıl Çalışır ?
Tablomuzun Class’ı
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Web; namespace TestConcurency { public class Learn { public int Id { get; set; } public string Name { get; set; } public Nullable<System.DateTime> CreDate { get; set; } [Timestamp] public byte[] RowVersion { get; set; } } } |
DbConcurrency’nin çalışma şekli şöyledir Dbdeki tabloya bir RowVersion adında bir alan açarsınız ve bu RowVersiona’a Timestamp attribute’ü eklersiniz bu her kayıt sonrasında kendi kendine değişecektir aslında diğer kullanıcı farklı bir RowVersion alacağı için kaydı güncelleyemecek.
(Update’in Get Metodu)
Hızlı bir örnek olması adına hızlı bir get metodu yazdım.
1 2 3 4 5 6 7 8 | public ActionResult Update(int id) { Model1 model1 = new Model1(); Learn learn = model1.Learn.Where(s => s.Id == id).SingleOrDefault(); return View(learn); } |
(Update’in View’ı)
Viewdaki en kritik şey aşağıdaki alanı hiddenfor olarak form içerisinde olmalı
@Html.HiddenFor(model=>model.RowVersion)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | @model TestConcurency.Learn @{ ViewBag.Title = "Update"; } <h2>Update</h2> @using (Html.BeginForm("Update","Home",FormMethod.Post)) { @Html.AntiForgeryToken() <div class="form-horizontal"> <h4>Learn</h4> <hr /> @Html.ValidationSummary(true, "", new { @class = "text-danger" }) @Html.HiddenFor(model => model.Id) @Html.HiddenFor(model=>model.RowVersion) <div class="form-group"> @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.CreDate, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.CreDate, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.CreDate, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> <div class="col-md-10"> @Html.HiddenFor(model => model.RowVersion, new { htmlAttributes = new { @class = "form-control" } }) </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <input type="submit" value="Save" class="btn btn-default" /> </div> </div> </div> } <div> @Html.ActionLink("Back to List", "Index") </div> <script src="~/Scripts/jquery-3.4.1.min.js"></script> <script src="~/Scripts/jquery.validate.min.js"></script> <script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script> |
(Update Post Metodu)
Update kısmında tüm propertyleri kaydedip yine gönderiyoruz normalde id ile sorgu atmamam gerekiyordu ama ben kafanız karışmasın diye öyle yapmak durumunda kaldım.
Not: buradaki mantık try catch ile bu exceptionu bulup kontrol etmek ve kullanıcıya validation vermek
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | [HttpPost] public ActionResult Update(Learn model) { using (Model1 db = new Model1()) { Learn learn = db.Learn.Where(s => s.Id == model.Id).SingleOrDefault(); learn.Name = model.Name; learn.RowVersion = model.RowVersion; learn.CreDate = model.CreDate; try { db.Entry(learn).OriginalValues["RowVersion"] = learn.RowVersion; db.Entry<Learn>(learn).State = System.Data.Entity.EntityState.Modified; db.SaveChanges(); } catch (DbUpdateConcurrencyException ex) { ViewBag.Validation = "Kayıt daha önce güncellenmiş lütfen sayfayı yenilerek tekrardan güncelleyiniz"; } } return View(); } |