Entity Kalıtım Özelliğinin Veritabanında Temsil Edilmesi

11 Mar

Nesneye yönelik programlama(OOP-Object Oriented Programming) yönteminin üç temel özelliği bulunmaktadır. Bunlar;

  • Encapsulation (Kapsülleme)
  • Polymorphism (Çok biçimlilik)
  • Inheritance (Kalıtım)

Bu yazının konusu, inheritance(kalıtım) özelliğinin veri tabanında temsil edilmesidir. Kalıtım, bir sınıfın bazı özelliklerini üst sınıftan almasına denir.

Örneğin bir uygulamadaki kullanıcıları, bireysel ve kurumsal olarak ayırarak temsil etmek istediğimizde nesneye yönelik bir tasarım kullanarak aşağıdaki gibi bir yapı oluşturabiliriz.

public class User
{
     public int Id { get; set; }
     public string Username { get; set; }
     public string Password { get; set; }
     public string Email { get; set; }
}

public class IndividualUser: User {    
     public string FirstName { get; set; }     
     public string LastName { get; set; } 
} 

public class CorporateUser: User {     
     public string Title { get; set; }     
     public string NationalTaxNumber { get; set; } 
}

Görüldüğü üzere, tek bir class tipi kullanarak tüm özellikleri(property) içerisine doldurmadık. Bunun yerine, User adında bir ana class ve IndividualUser, CorporateUser isimli iki alt class oluşturduk. Çünkü User class içerisindeki özellikler diğer class’lar için ortaktır.

Bu yapının, sadece programlama tarafında temsil edilmesi bizim için yeterli olmayacaktır. İlgili kayıtların aynı zamanda veritabanına kaydedilebilmesi gerekmektedir. Bu nedenle, veritabanında bu yapıya uygun bir çalışma yapmak gerekmektedir. Veritabanı tasarımı yapılırken Normal Form(NF) kuralları dikkate alınmalıdır.

Normal form kurallarının ihmal edilmesinin iki sebebi olabilir. Birincisi kurallardan haberdar olmamak. İkincisi, kurallarla uğraşmadan olayın kod tarafında çözülebileceğinin düşünmektir.

Normal Form kuralları bazı durumlarda ihlal edilebilmektedir.

Tek tablo kullanarak kural ihlali

Kurumsal ve Bireysel kullanıcıları tek bir tablo içerisinde tutmak istediğinizde, tüm alanlar tek bir tablo içerisinde bulundurulacaktır. Bu durumda bireysel kullanıcılar için Title ve NatianalTaxNumber alanları boş kalacak, kurumsal kullanıcılar için FirstName ve LastName alanları boş kalacaktır. Tabloda bir kolon ya nullable ya da non-nullable özellikte olmalıdır. Nullable kolonlar, feature için henüz elde edilememiş ancak elde edildiğinde girilecek olan alanlar için kullanılır. Oysa burada FirsName, LastName, Title, NationalTaxNumber gibi alanlar kayıt türüne göre olmazsa olmaz alanlardır.

IdUsernamePasswordEmailFirstNameLastNameTitleNatiaonaTaxNumber
1bob1232b@mail.comBobSmith
2corp1235c@crp.comCorp4656512
Tek tablo kullanımı

Tek tablo çözümlerinde bazen 1NF kuralları hiçe sayılabilmektedir. Örneğin tasarım yapılırken, Name diye bir alan açarak bireysel kullanıcılar için ad ve soyad birleştirilerek bu alana yazılıp, kurumsal kullanıcılar için şirket adı aynı kolona yazılabilmektedir. Bunlar 1NF kuralına aykırıdır. 1NF kuralları;

  • Tekrarlanan sütun yapıları olmamalıdır.
  • Birden fazla bilgi tek bir sütunda olamaz.
  • Bir alan içerisindeki bilgi özel karakterlerle ayrılarak tutulmamalıdır.

İki tablo kullanarak kural ihlali

Eğer bireysel ve kurumsal kullanıcılar için iki ayrı tablo tutulursa;

IdUsernamePasswordEmailFirstNameLastName
1bob1232b@mail.comBobSmith
IndividualUsers
IdUsernamePasswordEmailTitleNatiaonaTaxNumber
1corp1235c@crp.comCorp4656512
CorporateUsers

Bu durumda, müşteri ile ilişkilendirilecek olan bir tabloda hangi Id bilgisi tutulacak? 1 numaralı id bilgisi hem kurumsal hem de bireysel kullanıcı tablosunda bulunmaktadır. Örneğin Sipariş tablosuna ilişki kurulmak istendiğinde, iki tablo ile birden ilişki kurulmak durumunda kalınacaktır.

Üç tablo kullanarak kalıtım özellikli tasarım

Kalıtım özelliğini veritabanına yansıtarak bir tasarım oluşturmak, hem SOLID prensiplerine hem de OOP mantığına uygun olacaktır.

IdUsernamePasswordEmail
1bob1232b@mail.com
2corp1235c@crp.com
Users
UserIdFirstNameLastName
1BobSmith
IndividualUsers
UserIdTitleNatiaonaTaxNumber
2Corp4656512
CorporateUsers

Bu tasarıma sayesinde, bir önceki tasarımdaki ilişki sorunu çözülmüş olacaktır. Siparis tablosu ile ilişki kurulacak tablo Users tablosu olacaktır.

Postgresql Databse Table Diagram (Datagrip)

Artık kullanıcılar tek bir merkez tablodan(users) Id bilgisi elde edecektir. Yeni bir kullanıcı türü geldiğinde sistemin mevcut özellikleri bozulmadan yeni özellik ekleme(extensibility) sağlanmış olacaktır. Örneğin iot_users gibi cihaz temelli bir kullanıcıyı sisteme eklemek kolay olacaktır. Bu sayede sistem open/closed prensibine uyugun olacaktır.

Ekstra Bilgi

Bu tasarıma göre users tablosunda user_type gibi tür bilgileri tutulmamaktadır. Sorgulamalarda kolaylık olsun diye bu tür bir alan açıldığında, eğer kurumsal bir kullanıcı eklenirken yanlışlıkla kullanıcı türü bireysel olarak işaretlenirse veri tutarlılığı bozulacaktır. Bunun yerine kullanıcıların türlerine göre sayılarını raporlamak için örnek bir sorgu aşağıdaki gibi oluşturulabilir;

select type, count(*)
from (
      (select 'Individual' as type  from individual_users)
        union all
      (select 'Corporate' from corporate_users)
        union all
      (select 'IoT' from iot_users)
     ) tables
group by (type);

Özet

Programlama dünyasında kullanılan teknik ve prensipler, veritabanı için bir engel değildir. Birinde OOP kuralları uygulanırken, diğerinde Normal Form kuralları uygulanarak doğru tasarımlar yapılabilmektedir. Programlama yaparken kolaylık olsun diye veya SQL sorgulamalarında kolaylık olsun diye hatalı tasarıma yönelmek veri bütünlüğünü ve tutarlılığını bozabilir.