Derinlemesine yazılım eğitimleri için kanalımı takip edebilirsiniz...

Entity Framework Core – Owned Entities and Table Splitting

Merhaba,

Entity Framework Core tasarımlarında bir entity’nin olması gereken inşa kurallarının dışına çıkarak parçalamak ve grupsal olarak property’lerini farklı class’lar da tutmak isteyebiliriz. Bu class’lar, yapısal olarak entity type’a benzeyebilirler lakin davranışsal olarak, ana entity’nin farklı property’lerini temsil etmektedirler.

Entity Framework Core - Owned Entities and Table Splitting
Yukarıdaki görseli incelerseniz eğer, ‘Employee’ entity’sinin ‘Name’, ‘MiddleName’ ve ‘LastName’ bilgileri bir grup olarak ‘EmployeeName’ sınıfına, benzer mantıkla ‘StreetAdress’ ve ‘Location’ bilgileri ise ‘Address’ sınıfına alınmıştır. Bu grupsal property’leri barındıran entity type misali sınıflar nihai olarak ana entity’de navigation property olarak tarif edilmektedirler.

Normal EF Core kurallarında tüm entity’lerin bir primary key property’si olmalıdır. Haliyle EF Core navigation property’ler ile kurulan relation durumlarında ilişkisel olarak bu property üzerinden foreign key’leri sağlayacağını bilmektedirler. Halbuki buradaki amaç ne ilişkisel bir tasarım yapmak ne de primary key’i olmayan bir tablo oluşturmak. Buradaki amaç ‘Employee’ türünün property’lerini grupsal olarak farklı sınıflara dağıtmak ve o şekilde yönetmektir. İşte böyle veritabanı açısından normalizasyona aykırı tasarımların söz konusu olduğu durumlarda Owned Entities özelliği ile tasarımı ORM aracına izah edebilmekte ve bunların bir entity değil, var olan entity’nin alt parçaları olduğunu söyleyebilmekteyiz.

Bunun için context nesnesinin direkt ‘OnModelCreating’ metodunu kullanabileceğimiz gibi ayriyeten ‘IEntityTypeConfiguration<T>’ türünden bir konfigürasyon yapılanmasını da kullanabiliriz.

İlk olarak ‘OnModelCreating’ metodunda ilgili konfigürasyonu ele alırsak eğer :

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Employee>().OwnsOne(e => e.Address);
            modelBuilder.Entity<Employee>().OwnsOne(e => e.EmployeeName);
            base.OnModelCreating(modelBuilder);
        }

görüldüğü üzere ilgili ‘OwnsOne’ fonksiyonu sayesinde ‘Employee’ sınıfın altındaki ‘Address’ ve ‘EmployeeName’ navigation property’lerinin ilişkisel bir tablo değil, esasında alt property tanımlamalarını tutan gruplar olduğunu ifade etmiş bulunmaktayız.

Benzer işi ‘IEntityTypeConfiguration<T>’ interface’i ile gerçekleştirirsek eğer :

    class EmployeeConfiguration : IEntityTypeConfiguration<Employee>
    {
        public void Configure(EntityTypeBuilder<Employee> builder)
        {
            builder.OwnsOne(e => e.Address);
            builder.OwnsOne(e => e.EmployeeName);
        }
    }

İlgili interface’den türeyen ‘EmployeeConfiguration’ sınıfı üzerinde implement edilen ‘Configure’ metodunda yine ‘OwnsOne’ fonksiyonuyla ilgili property grupları belirtilmektedir. Bu tasarımdan sonra ilgili konfigürasyon dosyası, context sınfındaki ‘OnModelCreating’ fonksiyonunda aşağıdaki gibi ‘ApplyConfiguration’ metodu ile ilgili ORM’ye dahil edilmesi gerekmektedir.

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.ApplyConfiguration(new EmployeeConfiguration());
            base.OnModelCreating(modelBuilder);
        }

Normalde bu konfigürasyonları yapmasak EF Core ‘Employee’ altındaki ‘EmployeeName’ ve ‘Address’ property’lerini bir ilişkisel navigation property olarak algılayacak ve migration oluşturma sürecinde primary key kolonları tanımlanmadığı için aşağıdaki hatayı verecektir.

Amma velakin ‘OwnsOne’ metodu sayesinde ilgili property’lerin ilişkisel navigation property olmadığını, ilgili entity’nin property’lerini barındıran alt class’lar olduğunu bildirmiş olmaktayız. Dolayısıyla migration basarken bir problemle karşılaşılmayacak ve migrate neticesinde ilgili tabloyu aşağıdaki gibi generate edecektir.

Entity Framework Core - Owned Entities and Table SplittingYandaki görselde görüldüğü üzere ‘Employees’ entity’si içerisinde navigation property olarak bildirilen alt property grupları yapısal olarak ‘Employees’ tablosunda kolon olarak generate edilmişlerdir. Kolon isimlerine dikkat ederseniz hangi class’tan geliyorsa onu bildirecek şekilde nitelendirilmiştir. Eğer ki oluşturulacak kolonların ismini değiştirmek istiyorsanız ilgili property’lere aşağıdaki gibi müdahalede bulunmanız gerekmektedir.

            builder.OwnsOne(e => e.Address).Property(p => p.Location).HasColumnName("Location");
            builder.OwnsOne(e => e.Address).Property(p => p.StreetAddress).HasColumnName("StreetAddress");
            builder.OwnsOne(e => e.EmployeeName).Property(e => e.LastName).HasColumnName("LastName");
            builder.OwnsOne(e => e.EmployeeName).Property(e => e.MiddleName).HasColumnName("MiddleName");
            builder.OwnsOne(e => e.EmployeeName).Property(e => e.Name).HasColumnName("Name");

Entity Framework Core - Owned Entities and Table SplittingHaliyle bu şekilde yapılan bir çalışma neticesinde kolon isimleri istediğiniz gibi edinilebilmektedir. Görüldüğü üzere Table Splitting operasyonu neticesinde veritabanındaki herhangi bir tablonun karşılığı olan bir entity’i yazılım kısmında bölebilmekte ve bir bütün olarak kullanmaya devam edebilmekteyiz.

Owned Attribute’u
Entity bölme işlemini gerçekleştirebilmek için yukarıda ele alınan yöntem dışında ayriyeten ‘Owned’ attribute’unu kullanabilirsiniz. Bu attribute ile ana entity tarafından navigation property olarak referans edilen tüm parçaları işaretlemeniz ilişkisel bir tablo tasarımı olmadığına dair bilgilendirme yapmanız için yeterli olacaktır.

    class Employee
    {
        public int Id { get; set; }
        public bool IsActive { get; set; }
        public EmployeeName EmployeeName { get; set; }
        public Address Address { get; set; }
    }
    [Owned()]
    class EmployeeName
    {
        public string Name { get; set; }
        public string MiddleName { get; set; }
        public string LastName { get; set; }
    }
    [Owned()]
    class Address
    {
        public string StreetAddress { get; set; }
        public string Location { get; set; }
    }

İlgilenenlerin faydalanması dileğiyle…
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…

Bunlar da hoşunuza gidebilir...

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

*