EntityFramework Core’da Value Objeler (Owned Type)
Identity gerektirmeyen objelere value objeler denir, bu tip objeler domain driven design içinde sıkça kullanılır. Bu gönderide aynı zamanda owned type olarak bilinen bu türlerin ef core’a nasıl uygulanacağına bakacağız.
Record Type
Record C# 9 ile gelen bir referans türüdür. En büyük avantajı immutability, referans ve value eşitliğidir. Bildiğiniz gibi class’larda bir karşılaştırma olduğu zaman bellekteki referanslara bakılarak yapılır, fakat record ile value’leri de karşılaştırılır.
- Value Eşitliği
- Basit syntax
- Inherit için destek
- Mutaion
Örnek bir tasarımına bakalım
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public record SampleRecord(int X,int Y) { } //Equals: public record SampleRecord { public SampleRecord2(int x,int y) { X = x; Y = y; } public int X { get; init; } public int Y { get; init; } } |
Yazdığımız iki record da aynı anlama gelir birincisi syntax olarak daha basittir. Şimdi de eşitlik durumuna bakalım.
1 2 3 4 5 6 7 |
var test = new SampleClass(1, 1); var test2 = new SampleClass(1, 1); var isEqual = test == test2; // false var test = new SampleRecord(1, 1); var test2 = new SampleRecord(1, 1); var isEqual = test == test2; // true |
Görüldüğü gibi record karşılaştırma yaparken içindeki valueleri de karşılaştırırak yapar.
1 2 3 4 5 6 7 |
public record SampleRecord(int X,int Y) { public string[] Arr { get; init; } } //usage: var test = new SampleRecord(1, 1) { Arr = new string[] {"value"}}; |
Objeyi with keywordüyle kolayca aktarabilirsiniz. (mutaion)
1 2 3 4 5 6 |
var test2 = test with { }; //test3 is 1,1 var isEq = test == test2 //true var test3 = test with {Arr = new string[]{"test" }; //test3 is 1,1,string[]{test} ar isEq2 = test == test3 //false |
Inheritance
1 2 3 4 |
public abstract record BaseUser(string name, string lastName); public record Student(string name, string lastname,string school) : BaseUser(name,lastname); |
Entity Framework Core ile kullanımı
Örnek olarak bir User entity’miz ve bir de address bölümü olsun. Bu address bölümü her user’ın kendine ait spesifik bir alandır, yani birthDate, Name gibi alanlara denk gelir. Kompleks tipdir ve id’si yoktur. Ef core’da owned type olarak adlandırılır.
Mevcut tabloyla ilişki kurulabilmesi için owned type’lara bir gölge primary key yaratılır.
Address.cs
1 2 3 |
public record Location(string City, string Country, string Street, string Zipcode) { } |
User.cs
1 2 3 4 5 |
public class User { ///... public Location Address { get; set; } } |
ModelBuilder
1 2 |
modelBuilder.Entity<User>().OwnsOne(x => x.Address) .Property(ad => ad.City).HasColumnName("City"); |
Yukarıdaki durum için bir migration oluşturduğumuz zaman migration aşağıdaki gibi oluşacaktır.

Görüldüğü gibi owned type alanların columnları Address_Street, Address_Zipcode şeklinde oluştururken, City verdiğimiz isimle oluştu.
Owned Type’lar record tipinde yapmak zorunda değilsiniz, class ve struct gibi türlerde de yapabilirsiniz. Biz eşitlik karşılaştırması ve syntax’ı sebebiyle tercih ettik.
Ayrı bir tablo olarak saklama
Ayrıca owned type’larımızı farklı bir tablo oluşturp onda da saklayabiliriz. Fakat bu sadece veritabanı için bir değişikliktir, ef core’da yapı olarak birşey değişmeyecektir gene aynı yöntemi kullanacağız.
1 2 3 4 |
modelBuilder.Entity<User>().OwnsOne(x => x.Address) .ToTable("UserAddresses") .Property(x => x.City) .HasColumnName("City"); |
Migration:

Address columnu çekerken herhangi bir include yapmanıza gerek yok. Bu ilişiki 1’e 1 ilişkiye benzer olmasına rağmen sadece veritabanı şeması olarak benzerlikleri vardır.
Örnek bir query
1 |
var user = db.Users.FirstOrDefault(u => u.Address.City == "Ankara"); |
Attribute olarak da işaretleyebiliriz.
1 2 3 4 |
[Owned] public record Location(string City, string Country, string Street, string Zipcode) { } |
Kısıtlamalar
DbSet<T>
olarak çağıramazsınız- ModelBuilder içinde
Entity<T>
olarak çağıramazsınız.
Domain Driven Design’daki Rolü
Value objeler DDD’nin önemli bir parçasıdır. Domain modelleme yaparken ortak bir dil kullanırız (Ubiquitous Language), bu dil olabildiğince basit olmalı çünkü domain expert, developer gibi domain ile ilgili bütün bireylerin anlayacağı tarzda olmalı. Bu anlaşılabilirlik value objelerle daha da kolay olur örneğin Adres alanın çok fazla alanı olduğu varsayalım bu durumda tek tek User‘ın bir city, street gibi tanımlamalar yapacaktık. Halbuki bu durumda bir value obje tanımlamak sadece user değil kullanılacak tüm alanlar için bir tutarlılık ve kolaylık sağlayacaktır. Ayrıca gerçek dünya’daki kullanımına da çok yakın bir anlamı olacaktır.