Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
EF Core, yalnızca diğer varlık türlerinin gezinti özelliklerinde görünebilen varlık türlerini modellemenizi sağlar. Bunlara sahip olunan varlık türleri denir. Sahip olduğu varlık türüne sahip olan varlık onun sahibidir.
Sahip olunan varlıklar, temelde sahibin bir parçasıdır ve onsuz var olamazlar; bu durum kavramsal olarak yığınlara benzer. Bu, sahip olunan varlığın, sahiple ilişkinin bağımlı tarafında tanım gereği olduğu anlamına gelir.
İpucu
Bir değer nesnesini (veya Coordinate gibi kendi kimliği olmayan bir Address nesne) modellediyseniz, sahip olunan varlık türü yerine karmaşık bir tür kullanmayı göz önünde bulundurun. Sahip olunan türlerden farklı olarak, karmaşık türlerin değer semantiği vardır ve bir dizi tuzaktan kaçınan gizli anahtar yoktur; Karşılaştırma için bkz . Karmaşık türler ve sahip olunan varlık türleri .
Türleri sahip olunan olarak yapılandırma
Çoğu sağlayıcıda, varlık türleri hiçbir zaman kural gereği sahip olunan olarak yapılandırılmaz - türü sahiplik olarak yapılandırmak için açıkça OwnsOne yöntemini kullanmanız veya türünü OnModelCreating açıklama ekleyerek tanımlamanız gerekir. Azure Cosmos DB sağlayıcısı bunun bir özel durumudur. Azure Cosmos DB bir belge veritabanı olduğundan, sağlayıcı tüm ilgili varlık türlerini varsayılan olarak sahip olduğu şekilde yapılandırır.
Bu örnekte, StreetAddress kimlik özelliği olmayan bir türdür. Belirli bir siparişin sevkiyat adresini belirtmek için Sipariş türünün özelliği olarak kullanılır.
Başka bir varlık türünden başvurulduğunda onu sahip olunan bir varlık olarak işlemek için OwnedAttribute kullanabiliriz.
[Owned]
public class StreetAddress
{
public string Street { get; set; }
public string City { get; set; }
}
public class Order
{
public int Id { get; set; }
public StreetAddress ShippingAddress { get; set; }
}
OwnsOne yöntemini, OnModelCreating içinde kullanmak, ShippingAddress özelliğinin, Order varlık türünün Sahip Olunan Varlığı olduğunu belirtmek ve gerekirse ek öğeler yapılandırmak için de mümkündür.
modelBuilder.Entity<Order>().OwnsOne(p => p.ShippingAddress);
ShippingAddress özelliği türünde özelse Order yönteminin dize sürümünü OwnsOne kullanabilirsiniz:
modelBuilder.Entity<Order>().OwnsOne(typeof(StreetAddress), "ShippingAddress");
Yukarıdaki model aşağıdaki veritabanı şemasına eşlenmiştir:
Daha fazla bağlam için örnek projenin tamamına bakın.
İpucu
Sahip olunan varlık türü gerekli olarak işaretlenebilir, daha fazla bilgi için bkz: Gerekli birbiri bağımlı varlıklar.
Gizli anahtarlar
OwnsOne ile veya bir başvuru navigasyonu aracılığıyla yapılandırılan veya keşfedilen sahiplik türleri, her zaman sahibiyle bire bir ilişkiye sahiptir; bu nedenle, yabancı anahtar değerleri benzersiz olduğu için kendi anahtar değerlerine ihtiyaç duymazlar. Önceki örnekte, StreetAddress türünün bir anahtar özelliği tanımlaması gerekmez.
EF Core'un bu nesneleri nasıl izlediğini anlamak için, birincil anahtarın sahip olunan tür için gölge özelliği olarak oluşturulduğunu bilmek yararlıdır. Sahip olunan türün bir örneğinin anahtarının değeri, sahip örneğin anahtarının değeriyle aynı olacaktır.
Sahip olunan tür koleksiyonları
Sahip olunan türler koleksiyonunu yapılandırmak için OwnsMany içinde kullanın OnModelCreating.
Sahip olunan türlerin birincil anahtara ihtiyacı vardır. .NET türünde iyi aday özellikleri yoksa EF Core bir tane oluşturmayı deneyebilir. Ancak, sahip olunan türler bir koleksiyon aracılığıyla tanımlandığında, sahibi üzerinde yabancı anahtar ve sahip olunan örneğin birincil anahtarı olarak hareket eden bir gölge özellik yaratmak (tıpkı OwnsOne için yaptığımız gibi) yeterli değildir: her sahip için birden fazla sahip olunan tür örneği olabilir ve bu nedenle, sahibin anahtarı her sahip olunan örneğine benzersiz bir kimlik sağlamak için yeterli olmaz.
Bunun en basit iki çözümü şunlardır:
- Birincil anahtarı temsil eden yedek bir anahtar, sahibine işaret eden yabancı anahtardan bağımsız yeni bir özellik üzerinde tanımlama. İçerilen değerlerin tüm sahipler arasında benzersiz olması gerekir (örneğin, Üst {1} öğe Alt {1} öğeye sahipse, Üst {2} öğe Alt {1} öğeye sahip olamaz), dolayısıyla değerin özgün bir anlamı yoktur. Yabancı anahtar birincil anahtarın bir parçası olmadığından değerleri değiştirilebilir, bu nedenle bir alt nesneyi bir üst nesneden diğerine taşıyabilirsiniz, ancak bu genellikle küme semantiklerine aykırıdır.
- Bileşik anahtar olarak yabancı anahtarı ve ek bir özelliği kullanma. Ek özellik değerinin artık yalnızca belirli bir ebeveyn için benzersiz olması yeterlidir (bu nedenle, Ebeveyn {1} Çocuk {1,1}'a sahipse, Ebeveyn {2} yine de Çocuk {2,1} öğeye sahip olabilir). Birincil anahtarın bir parçası yapılarak, yabancı anahtar sayesinde sahip ve sahip olunan varlık arasındaki ilişki değiştirilmez hale gelir ve bu, toplam semantiği daha iyi yansıtır. EF Core varsayılan olarak bunu yapar.
Bu örnekte sınıfını Distributor kullanacağız.
public class Distributor
{
public int Id { get; set; }
public ICollection<StreetAddress> ShippingCenters { get; set; }
}
Varsayılan olarak, gezinti özelliği ShippingCenters("DistributorId", "Id") aracılığıyla "DistributorId" başvurulan sahip olunan tür için kullanılan birincil anahtar FK ve "Id" benzersiz int bir değerdir.
Farklı bir birincil anahtarı yapılandırmak için HasKey çağrısı yapın.
modelBuilder.Entity<Distributor>().OwnsMany(
p => p.ShippingCenters, a =>
{
a.WithOwner().HasForeignKey("OwnerId");
a.Property<int>("Id");
a.HasKey("Id");
});
Yukarıdaki model aşağıdaki veritabanı şemasına eşlenmiştir:
Tablo bölme ile sahip olunan türleri eşleme
İlişkisel veritabanları kullanılırken, varsayılan olarak referans türleri sahiple aynı tabloya eşlenir. Bunun için tablonun ikiye bölünmesi gerekir: bazı sütunlar sahibin verilerini depolamak için, bazı sütunlar ise sahip olunan varlığın verilerini depolamak için kullanılır. Bu, tablo bölme olarak bilinen yaygın bir özelliktir.
Varsayılan olarak, EF Core sahip olunan varlık türünün özellikleri için veritabanı sütunlarını Navigation_OwnedEntityProperty adlandırma deseni ile adlandırır. Bu nedenle StreetAddress , özellikler 'Orders' tablosunda 'ShippingAddress_Street' ve 'ShippingAddress_City' adlarıyla görünür.
Bu sütunları yeniden adlandırmak için yöntemini kullanabilirsiniz HasColumnName .
modelBuilder.Entity<Order>().OwnsOne(
o => o.ShippingAddress,
sa =>
{
sa.Property(p => p.Street).HasColumnName("ShipsToStreet");
sa.Property(p => p.City).HasColumnName("ShipsToCity");
});
Not
Ignore gibi normal varlık türü yapılandırma yöntemlerinin çoğu aynı şekilde çağrılabilir.
Aynı .NET türünü birden çok sahip olunan tür arasında paylaşma
Sahip olunan varlık türü başka bir sahip olunan varlık türüyle aynı .NET türünde olabilir, bu nedenle .NET türü sahip olunan bir türü tanımlamak için yeterli olmayabilir.
Bu gibi durumlarda sahipten sahip olan varlığa işaret eden özellik, sahip olunan varlık türünün tanımlama gezintisi olur. EF Core açısından bakıldığında, tanımlama gezintisi .NET türüyle birlikte türün kimliğinin bir parçasıdır.
Örneğin, aşağıdaki sınıfta ShippingAddress ve BillingAddress ikisi de aynı .NET türündedir. StreetAddress
public class OrderDetails
{
public DetailedOrder Order { get; set; }
public StreetAddress BillingAddress { get; set; }
public StreetAddress ShippingAddress { get; set; }
}
EF Core'un bu nesnelerin izlenen örneklerini nasıl ayırt ettiğini anlamak için, tanımlayıcı gezintinin sahibin anahtarının ve sahip olunan türün .NET türünün değeriyle birlikte örneğin anahtarının bir parçası haline geldiğini düşünmek yararlı olabilir.
İç içe sahip olunan türler
Bu örnekte, OrderDetails, hem BillingAddress hem de ShippingAddress türlerine sahip olan StreetAddress türleridir. Ardından OrderDetails türüne DetailedOrder aittir.
public class DetailedOrder
{
public int Id { get; set; }
public OrderDetails OrderDetails { get; set; }
public OrderStatus Status { get; set; }
}
public enum OrderStatus
{
Pending,
Shipped
}
Sahip olunan bir türe yapılan her gezinti, tamamen bağımsız yapılandırmaya sahip ayrı bir varlık türü tanımlar.
İç içe geçmiş sahip olunan türlere ek olarak, bir sahip olunan tür, sahip olunan varlık bağımlı tarafta yer aldığı sürece sahip olan veya farklı bir varlık olabilen normal bir varlığa referans verebilir. Bu özellik sahip olunan varlık türlerini EF6'daki karmaşık türlerden farklı olarak ayarlar.
public class OrderDetails
{
public DetailedOrder Order { get; set; }
public StreetAddress BillingAddress { get; set; }
public StreetAddress ShippingAddress { get; set; }
}
Mülkiyet türlerini yapılandırma
Bu modeli yapılandırmak için OwnsOne metodunu akıcı bir şekilde zincirleme şeklinde çağırmak mümkündür.
modelBuilder.Entity<DetailedOrder>().OwnsOne(
p => p.OrderDetails, od =>
{
od.WithOwner(d => d.Order);
od.Navigation(d => d.Order).UsePropertyAccessMode(PropertyAccessMode.Property);
od.OwnsOne(c => c.BillingAddress);
od.OwnsOne(c => c.ShippingAddress);
});
Sahibine WithOwner işaret eden gezinti özelliğini tanımlamak için kullanılan çağrıya dikkat edin. Sahiplik ilişkisinin parçası olmayan sahip varlık türüne bir gezinme tanımlamak için WithOwner() bağımsız değişken olmadan çağrılmalıdır.
Bu sonucu, hem OwnedAttribute hem de OrderDetails üzerinde StreetAddress kullanarak elde etmek de mümkündür.
Buna ek olarak, Navigation çağrısına dikkat edin. Sahip olunan türlere yönelik gezinti özellikleri, sahip olunmayan türlerin gezinti özelliklerinde olduğu gibi daha fazla yapılandırılabilir.
Yukarıdaki model aşağıdaki veritabanı şemasına eşlenmiştir:
Sahip olunan türleri ayrı tablolarda depolama
Ayrıca EF6 karmaşık türlerinden farklı olarak, sahip olunan türler sahibinden ayrı bir tabloda depolanabilir. Sahip olunan bir türü sahiple aynı tabloya eşleyen kuralı geçersiz kılmak için, çağırmanız ToTable ve farklı bir tablo adı sağlamanız yeterlidir. Aşağıdaki örnek, OrderDetails ve iki adresini DetailedOrder ile ayrı bir tabloya eşleyecektir.
modelBuilder.Entity<DetailedOrder>().OwnsOne(p => p.OrderDetails, od => { od.ToTable("OrderDetails"); });
Bunun için TableAttribute kullanmak da mümkündür, ancak sahip olunan türde birden fazla gezinti olduğunda bu başarısız olacaktır; çünkü böyle bir durumda birden fazla varlık türü aynı tabloya eşlenir.
Sahip olunan türleri sorgulama
Sahibi sorgularken sahip olunan türler varsayılan olarak eklenir. Sahip olunan türler ayrı bir tabloda depolanmış olsa bile, Include yöntemini kullanmak gerekli değildir. Daha önce açıklanan modele bağlı olarak, aşağıdaki sorgu veritabanından Order, OrderDetails ve sahip olunan iki StreetAddresses öğesini alacaktır.
var order = await context.DetailedOrders.FirstAsync(o => o.Status == OrderStatus.Pending);
Console.WriteLine($"First pending order will ship to: {order.OrderDetails.ShippingAddress.City}");
Sınırlamalar
Bu sınırlamalardan bazıları sahip olunan varlık türlerinin çalışma şekli için temeldir, ancak bazıları da gelecek sürümlerde kaldırabilmemiz gereken kısıtlamalardır:
Tasarıma göre kısıtlamalar
- Bir sahiplik türü için
DbSet<T>oluşturamazsınız. - üzerinde
Entity<T>()sahip olunan bir türle çağrıModelBuilderyapamazsınız. - Sahip olunan varlık türlerinin örnekleri birden çok sahip tarafından paylaşılamaz (bu, sahip olunan varlık türleri kullanılarak uygulanamayan değer nesneleri için iyi bilinen bir senaryodur).
Geçerli eksiklikler
- Sahip olunan varlık türlerinin devralma hiyerarşileri olamaz
Önceki sürümlerdeki eksiklikler
- EF Core 2.x'te sahip olunan varlık türlerine yönelik başvuru gezintileri, sahipten ayrı bir tabloya açıkça eşlenmedikleri sürece null olamaz.
- EF Core 3.x'te sahibinle aynı tabloya eşlenmiş bağımlı varlık türlerinin sütunları her zaman nullable veya null yapılabilir olarak işaretlenir.