Sahip Olunan Varlık Türleri

EF Core, yalnızca diğer varlık türlerinin gezinti özelliklerinde görünebilen varlık türlerini modeletmenize olanak tanır. Bunlara sahip olan varlık türleridenir. Sahip olduğu varlık türü içeren varlık sahibi.

Sahibi olan varlıklar aslında sahibin bir parçasıdır ve bu olmadan mevcut olamaz, bu değerler toplamalarakavramsal olarak benzerdir. Bu, sahip olduğu varlığın, sahip olduğu ilişkinin bağımlı tarafında tanımına göre olduğu anlamına gelir.

Türleri sahipsiz olarak yapılandırma

Çoğu sağlayıcıda, varlık türleri kurala göre hiçbir şekilde yapılandırılmamıştır; türü sahip olarak OwnsOne yapılandırmak için içinde metodunu açık olarak kullanmanız OnModelCreating veya öğesine Not eklemek zorundasınız OwnedAttribute . Azure Cosmos DB sağlayıcı bu için bir özel durumdur. Cosmos DB bir belge veritabanı olduğundan, sağlayıcı tüm ilgili varlık türlerini varsayılan olarak sahip olduğu gibi yapılandırır.

Bu örnekte, StreetAddress Identity özelliği olmayan bir türdür. Bu, belirli bir siparişin sevkiyat adresini belirtmek için sipariş türünün bir özelliği olarak kullanılır.

OwnedAttributeBaşka bir varlık türünden başvuruluyorsa onu sahip olan bir varlık olarak değerlendirmek için ' i 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; }
}

Ayrıca, OwnsOneOnModelCreatingShippingAddress özelliğinin varlık türünün sahip olduğu bir varlık olduğunu belirtmek ve gerekirse ek modeller yapılandırmak için ' de metodunu kullanmak mümkündür Order .

modelBuilder.Entity<Order>().OwnsOne(p => p.ShippingAddress);

ShippingAddressÖzelliği tür içinde Private ise Order , yönteminin dize sürümünü kullanabilirsiniz OwnsOne :

modelBuilder.Entity<Order>().OwnsOne(typeof(StreetAddress), "ShippingAddress");

Yukarıdaki model aşağıdaki veritabanı şemasına eşlendi:

Sahip başvurusunu içeren varlık için veritabanı modelinin Sceenshot 'ı

Daha fazla bağlam için bkz. tam örnek proje .

İpucu

Sahip olan varlık türü gerekli olarak işaretlenebilir, daha fazla bilgi için bkz. bire bir bağımlıya bakın.

Örtük anahtarlar

OwnsOneBir başvuru gezintisi aracılığıyla yapılandırılan veya keşfedilen sahipli türler her zaman sahibiyle bire bir ilişkiye sahiptir, bu nedenle yabancı anahtar değerleri benzersiz olduğundan kendi anahtar değerlerine gerek kalmaz. Önceki örnekte, StreetAddress türün bir anahtar özelliği tanımlamasına gerek yoktur.

EF Core bu nesneleri nasıl izlediğini anlamak için, bir birincil anahtarın, sahip olduğu tür için bir Gölge Özellik olarak oluşturulduğunu bilmeniz yararlı olur. Sahip türünün bir örneğinin anahtarı değeri, sahip örneği anahtarının değeri ile aynı olacaktır.

Sahip olunan türlerin koleksiyonları

İçinde kullanım türlerinin bir koleksiyonunu yapılandırmak için OwnsManyOnModelCreating .

Sahip olunan türlerin bir birincil anahtar olması gerekir. .NET türünde iyi aday özellikleri yoksa EF Core bir tane oluşturmayı deneyebilir. Bununla birlikte, sahip olunan türler bir koleksiyon aracılığıyla tanımlandığında yalnızca bir gölge özellik oluşturmak için, bizim için yaptığımız gibi, hem yabancı anahtar hem de sahibi olan Örneğin birincil anahtarı olarak davranır OwnsOne . her sahip için birden çok sahip tür örneği olabilir ve bu nedenle sahip anahtarı, sahip olunan her örnek için benzersiz bir kimlik sağlamak için yeterli değildir.

Bunun en kolay iki çözümü şunlardır:

  • Yeni bir özellikte, sahibine işaret eden yabancı anahtardan bağımsız olarak bir vekil birincil anahtar tanımlama. İçerilen değerlerin tüm sahiplerin benzersiz olması gerekir (örneğin, üst öğe alt öğesi varsa üst öğesi alt öğesi olamaz {1}{1}{2}{1} ), bu nedenle değerin hiç bir anlamı yoktur. Yabancı anahtar birincil anahtarın parçası olmadığından, değerleri değiştirilebilir, bu nedenle alt öğeyi bir üst öğeden diğerine taşıyabilirsiniz, ancak bu genellikle toplam semantiğe karşı gider.
  • Yabancı anahtar ve ek bir özelliği bileşik anahtar olarak kullanma. Ek özellik değerinin artık yalnızca belirli bir üst öğe için benzersiz olması gerekir (Bu nedenle, üst öğe alt öğesi varsa {1}{1,1} üst öğesi {2} hala alt öğeye sahip olabilir {2,1} ). Birincil anahtarın yabancı anahtar bölümünü, sahibi ve sahibi olan varlık arasındaki ilişki sabit hale gelir ve toplam semantiğini daha iyi yansıtır. Varsayılan olarak EF Core budur.

Bu örnekte, Distributor sınıfını kullanacağız.

public class Distributor
{
    public int Id { get; set; }
    public ICollection<StreetAddress> ShippingCenters { get; set; }
}

Varsayılan olarak, gezinti özelliği aracılığıyla başvurulan sahip türü için kullanılan birincil anahtar, ShippingCenters("DistributorId", "Id") FK olduğu "DistributorId" ve "Id" benzersiz bir int değerdir.

Farklı bir birincil anahtar çağrısı yapılandırmak için HasKey .

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şlendi:

Sahip olunan koleksiyonu içeren varlık için veritabanı modelinin Sceenshot 'ı

Sahip olunan türleri tablo bölme ile eşleme

İlişkisel veritabanları kullanılırken, varsayılan başvuruya ait türler, sahibiyle aynı tabloyla eşleştirilir. Bu, tablonun iki içinde bölünmesini gerektirir: bazı sütunlar sahibin verilerini depolamak için kullanılacaktır ve bu varlığın verilerini depolamak için bazı sütunlar kullanılacaktır. Bu, tablo bölmeolarak bilinen yaygın bir özelliktir.

Varsayılan olarak, EF Core, model Navigation_OwnedEntityPropertytakip eden varlık türünün özelliklerine ait veritabanı sütunlarını adı verecek. Bu nedenle, StreetAddress Özellikler ' ShippingAddress_Street ' ve ' ShippingAddress_City ' adlarıyla ' Orders ' tablosunda görünür.

HasColumnNameBu sütunları yeniden adlandırmak için yöntemini kullanabilirsiniz.

modelBuilder.Entity<Order>().OwnsOne(
    o => o.ShippingAddress,
    sa =>
    {
        sa.Property(p => p.Street).HasColumnName("ShipsToStreet");
        sa.Property(p => p.City).HasColumnName("ShipsToCity");
    });

Not

Yok sayma gibi normal varlık türü yapılandırma yöntemlerinin çoğu aynı şekilde çağrılabilir.

Aynı .NET türünü sahip olunan birden çok tür arasında paylaşma

Sahip olunan bir varlık türü, sahip olduğu başka bir varlık türüyle aynı .NET türünde olabilir, bu nedenle .NET türü, sahip olunan bir türü belirlemek için yeterli olmayabilir.

Bu gibi durumlarda, sahibi olan varlığa işaret eden özellik sahip olan varlık türü için gezinme haline gelir. EF Core perspektifinden, 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 her ikisi de aynı .net türüdür StreetAddress .

public class OrderDetails
{
    public DetailedOrder Order { get; set; }
    public StreetAddress BillingAddress { get; set; }
    public StreetAddress ShippingAddress { get; set; }
}

EF Core, bu nesnelerin izlenen örneklerini nasıl ayıracağınızı anlamak için, tanımlama gezintisinin, sahip olduğu türün değeri ve sahip olduğu .NET türü ile birlikte örnek anahtarının bir parçası haline geldiğini düşünmek yararlı olabilir.

İç içe sahip türler

Bu örnekte OrderDetailsBillingAddressShippingAddress , ve her iki türü de vardır StreetAddress . Daha sonra OrderDetailsDetailedOrder türüne 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 olan bir türe her gezinti, tamamen bağımsız yapılandırmayla ayrı bir varlık türü tanımlar.

Sahip olunan iç içe geçmiş türlerine ek olarak sahip olan bir tür, sahip olan varlık bağımlı tarafta olduğu sürece sahip veya farklı bir varlık olabilen bir normal varlığa başvurabilir. Bu yetenek, sahip olduğu varlık türlerini EF6 içindeki karmaşık türlerden ayrı olarak ayarlar.

public class OrderDetails
{
    public DetailedOrder Order { get; set; }
    public StreetAddress BillingAddress { get; set; }
    public StreetAddress ShippingAddress { get; set; }
}

Sahip olunan türleri yapılandırma

OwnsOneBu modeli yapılandırmak için bu yöntemi akıcı bir çağrıda zincirlemek 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);
    });

WithOwnerSahibe doğru işaret eden gezinti özelliğini tanımlamak için kullanılan çağrıya dikkat edin. Sahiplik ilişkisinin bir parçası olmayan sahip varlık türü için bir gezinti tanımlamak için WithOwner() herhangi bir bağımsız değişken olmadan çağrılmalıdır.

Ayrıca, ve kullanarak bu sonuca ulaşmak mümkündür OwnedAttributeOrderDetailsStreetAddress .

Ayrıca, çağrıya dikkat edin Navigation . EFCore 5,0 ' de, sahip olunan türler için gezinti özellikleri, sahip olmayan gezinti özellikleri içindaha fazla yapılandırılabilir.

Yukarıdaki model aşağıdaki veritabanı şemasına eşlendi:

İç içe ait başvuruları içeren varlık için veritabanı modelinin ekran görüntüsü

Sahip olunan türleri ayrı tablolarda depolama

Ayrıca, EF6 karmaşık türlerin aksine, sahip olunan türler sahibinden ayrı bir tabloda depolanabilir. Sahip olan bir türü sahip ile aynı tabloya eşleyen kuralı geçersiz kılmak için, yalnızca ToTable farklı bir tablo adı çağırıp bu adı sağlayabilirsiniz. Aşağıdaki örnek, OrderDetails ve iki adresini öğesinden ayrı bir tabloyla eşleşmeyecektir DetailedOrder :

modelBuilder.Entity<DetailedOrder>().OwnsOne(p => p.OrderDetails, od => { od.ToTable("OrderDetails"); });

Bunu TableAttribute gerçekleştirmek için de kullanabilirsiniz, ancak bu, sahip olan türde birden çok gezinmeler varsa, bu durumda birden çok varlık türünün aynı tabloyla eşlenmesi durumunda başarısız olacağını unutmayın.

Sahip olunan türler sorgulanıyor

Sahibi sorgulanırken sahip olan türler varsayılan olarak dahil edilir. IncludeSahip olan türler ayrı bir tabloda depolansa bile yöntemini kullanmak gerekli değildir. Daha önce açıklanan modele bağlı olarak aşağıdaki sorgu alınır OrderOrderDetails ve veritabanına ait olan iki sahip olur StreetAddresses :

var order = context.DetailedOrders.First(o => o.Status == OrderStatus.Pending);
Console.WriteLine($"First pending order will ship to: {order.OrderDetails.ShippingAddress.City}");

Sınırlamalar

Bu sınırlamaların bazıları, sahip olduğu varlık türlerinin çalışması için temeldir, ancak bazı diğerleri sonraki sürümlerde kaldırabilecekler konusunda daha fazla kısıtlamayla karşılaşabilirsiniz:

Tasarıma göre kısıtlamalar

  • DbSet<T>Sahip olunan bir tür için oluşturamazsınız.
  • Entity<T>()Üzerinde sahip olan bir tür ile çağrılamaz ModelBuilder .
  • Sahip varlık türlerinin örnekleri birden çok sahip tarafından paylaşılamaz (Bu, sahip olduğu varlık türleri kullanılarak uygulanamaz değer nesneleri için iyi bilinen bir senaryodur).

Geçerli eksikler

  • Sahip olan varlık türlerinde devralma hiyerarşileri olamaz

Önceki sürümlerde shortcomler

  • EF Core 2. x başvuru gezginlerinin sahip olduğu varlık türleri, sahip tarafından ayrı bir tabloya açıkça eşlenmedikleri müddetçe null olamaz.
  • EF Core 3. x içinde, sahip ile aynı tabloya eşlenmiş sahip olan varlık türlerinin sütunları her zaman null yapılabilir olarak işaretlenir.