Bir önce ki yazıda Veri Açıklaması/DataAnnotations isim uzayını inceledik. Veri açıklamaları ile veri moleliniz üzerinde property seviyesinde doğrulama mantığımızı çalıştırabiliyoruz. Veri modeli sınıflarınıza .NET 4 tarafından tamamen desteklenen [Range], [RegulerExpress] gibi doğrulama nitelikleri ekleyerek veri tabanı işlemleri yapmadan önce gerçekten kolay bir şekilde doğrulama kontrolüne zorlayabiliyoruz.
Property seviyesindeki doğrulama çok işe yaramasına rağmen tüm veri doğrulama ihtiyaclarmızı karşılamamaktadır. Veri modeli sınıfımızdaki bir çok property değerinin birlikte kontrol edileceği sınıf seviyesinde kontrol gerekmektedir.
System.ComponentModel.DataAnnotation isin uzayında bulunan IValidateableObject arayüzü ile entity nesnelerinize sınıf seviyesinde doğrulama ekleyebilirsiniz.
Bu serinin daha önce ki yazılarnda ki gibi bir adres defteri uygulaması üzerinden sınıf seviyesinde doğrulama nasıl yapılır inceleyelim. Aşağıda ki örnekte kişi tanımlarını taşıyan Person entity sınıfımız yer almaktadır. Yapmak isteğimiz adres defterinde ki her erkeğin şirket bilgisinin her bayanında doğum günü bilgisinin boş bırakılmamasını sağlamak. Bu kuralı işletebilmek için aynı anda en az iki property değirini kontrol etmemiz gerekmektedir.
[cs]
public partial class Person : IValidatableObject
{
public int PersonId { get ; set ; }
public string FullName { get ; set ; }
public string Company { get ; set ; }
public DateTime ? BirthDay { get ; set ; }
public bool IsFemale { get ; set ; }
public virtual List Adresses { get ; set ; }
public IEnumerableValidate(ValidationContext validationContext)
{
if (IsFemale && BirthDay == null )
yield return new
ValidationResult (
"Bayanların doğum günü boş bırakılamaz" ,
new [] { "BirthDay" });
if (!IsFemale && string .IsNullOrEmpty (Company ))
yield return new
ValidationResult (
"Erkeklerin şirket bilgisi boş bırakılamaz" ,
new [] { "Company" });
}
}
Yukarıda ki kod bloğunda erkeğin adres bilgisi ve bayanın doğum günü bilgisi kontrol edilmektedir. IValidateableObject.Validate() metodu bir çok property değerini kontrol etmekte ve bir çok doğrulama hatası dönebilmektedir. Doğrulama hatalarının birinci parametresi hata mesajıdır. İkinci parametre ise hataya sebeb olan property isimleri dizisidir.
Otomatik Doğrulamaya Zorlamak
Entity Framework Code First IValidateableObject arayüzünü uygulayan entity neslerini kayıt ederken Validate metodunu otomatik olarak çağırmaktadır. Validate metodunu çağırmak için her hangi bir kod yazmanıza gerek yoktur. DbContext.SaveChanges() metodunu çağırdığınızda IValidateableObject.Validate EF Code First tarafından çağırılacak ve eğer hata oluşursa tüm transaction otomatik olarak geri alınacaktır.
[cs]
var person = new Person
{
FullName = "Ali Veli" ,
IsFemale = false ,
BirthDay = new DateTime (2000, 1, 1)
};
var dbContext = new AdressBook ();
dbContext.Persons .Add (person);
// Ali Veli kişi kaydını IvalidateableObject.Validate
// metodunda ki kurala uymadığı için
// aşağıda ki satırda exception throw edecektir
dbContext.SaveChanges ();
Hatanın throw edilmesi her zaman istenmeyen bir durumdur. Çünkü throw edilen hatanın arayüze yakın bir yerde catch edilmesi gerekmektedir. Bu sebebden entity nesnenizi kontrol etmek ve eğer veri iş kurallarına uygunsa veri tabanı işlemleri yapmak isteriz. SaveChanges() metodunu çağırmadan önce GetValidationErrors() metodu ile doğrulama hatalarını throw edilmeden elde ederiz.
[cs]
var person = new Person
{
FullName = "Ali Veli" ,
IsFemale = false ,
BirthDay = new DateTime (2000, 1, 1)
};
var dbContext = new AdressBook ();
dbContext.Persons .Add (person);
// tüm hataları listele
var errors = dbContext.GetValidationErrors ();
if (errors.Count () > 0 )
// hataları ekranda göster
errors.ToList ().ForEach (
c=>c.ValidationErrors .ToList ().ForEach (
l=>ModelState .AddModelError (l.PropertyName ,l.ErrorMessage )));
else
dbContext.SaveChanges ();
Arayüz Entegrasyonu
Bir önce ki yazıda DataAnnotation isim uzayının .NET 4 ile getiştirilen tüm platformlar tarafından desteklendiğine değinmiştik. MVC 3 ile entity sınıfını hazırladığımız adres defteri uygulamamızı geliştirelim ve sınıf seviyesinde doğrulama işleminin önyüzde nasıl bir etki oluşturduğunu görelim. Öncelikle bir PersonController sınıfına göz atalım.
[cs]
public ActionResult Create ()
{
return View ();
}
[HttpPost ]
public ActionResult Create (Person person)
{
if (ModelState .IsValid )
{
var adressBook = new AdressBook ();
adressBook.Persons .Add (person);
adressBook.SaveChanges ();
return RedirectToAction ("Index" );
}
return View (person);
}
Yukarıda standart MVC Controller sınıfı kodlaması bulunmaktadır. İlk Create motodu ile arayüz hazırlanmakta ve ikinci Create(person) metodu ile kullanıcının girdiği Person verisi veri tabanına kayıd edilmektedir. Create(person ) metodu öncelikle gelen verinin doğrulamaları geçmesini eklemektedir. Eğer doğrulamaları geçti ise veri tabanına kayıt etmektedir. Veri doğrulama için ekstra hiçbir kodlama bulunmamaktadır. Veri doğrulaması DataAnnotation isim uzayına duyarlı MVC tarafından otomatik olarak yapılmaktadır. Birde önyüzü inceleyelim. Aşağıdaki Create() metodunun döndüğü ön yüz görülmektedir. Burada da hiçbir fazladan kodlama yok.
@model RoC.CodeFirst.Models.Person
@{
ViewBag.Title = "ViewPage1" ;
}
<h2> ViewPage1</h2>
<script src=" @Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src=" @Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
@ using (Html.BeginForm()) {
@ Html.ValidationSummary(true )
<fieldset>
<legend> Person</legend>
<div class="editor-label">
@ Html.LabelFor(model => model.FullName)
</div>
<div class="editor-field">
@ Html.EditorFor(model => model.FullName)
@ Html.ValidationMessageFor(model => model.FullName)
</div>
<div class="editor-label">
@ Html.LabelFor(model => model.Company)
</div>
<div class="editor-field">
@ Html.EditorFor(model => model.Company)
@ Html.ValidationMessageFor(model => model.Company)
</div>
<div class="editor-label">
@ Html.LabelFor(model => model.BirthDay)
</div>
<div class="editor-field">
@ Html.EditorFor(model => model.BirthDay)
@ Html.ValidationMessageFor(model => model.BirthDay)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
@ Html.ActionLink("Back to List" , "Index" )
</div>
Yukarıda ki Controller ve View entegrasyonu ile fazladan hiçbir doğrulama mantığı kodlamadık. Doğrulama mantığını tamamen veri modeli üzerine taşıdık. İş mantığının yazıldığı Controller sınıfı sadece ModelState.IsValid() fonksiyonu ile doğrulama sonucunu kontrol etti.
Eğer IValidateableObject.Validate() metodundan bir doğrulama hatası dönerse ModelState.IsValid otomatik false değerini alacaktır. Controller’ın ModelState.IsValid false değerini alınca View geri döndürdüğünü görülmektedir. Arayüz tekrar gösterilirken IValidateable.Validation() metodunun sonucları ValidationMessageFor metodu ile arayüzde gösterilecektir Sonuç olarak hatalı bir işlemi kayıd etmeye çalıştığımızda aşağıdaki ekran görüntüsüne ulaşırız.
Veri açıklaması/DataAnnotation ve sınıf seviyesinden doğrulama/IValidateableObject ile Entity Framework Code First bir çok uygulamanın doğrulama ihtiyaçlarına cevap vermektedir.
Sonuç
Entity Framework Code First ile birlikte doğrulama ve iş kurallarının veri modeli üzerinde kalması sağlanmıştır. Hedeflenen kendini tekrar etmeyen kodlama (DRY – Dont Repeat Yourself) yapabilmektir. Tüm iş kodları bir yerde bulunsun, basit okunabilir kodlamalar olsun ve asla iş kodları farklı yerlerde tekrar edilmesin istenmektedir. En çok tekrar edilen kodlama ise doğrulama kodlamasıdır. Hem istemci hem sunucu tarafında aynı veri kontrolleri yapılmaktadır. EF Code First (ve MVC 3) ile sunulan veri açıklaması ve sınıf seviyesi doğrulama çözümleri ile kendini tekrar eden doğrulama kodlamalarına çözüm getirmektedir.
Hiç yorum yok:
Yorum Gönder