İlişkilerde yabancı ve asıl anahtarlar

Bire bir ve bire çok ilişkilerin tümü, bağımlı uçta, asıl uçta birincil veya alternatif anahtara başvuran bir yabancı anahtar tarafından tanımlanır. Kolaylık olması için, bu birincil veya alternatif anahtar ilişki için "asıl anahtar" olarak bilinir. Çoka çok ilişkiler, her biri asıl anahtara başvuran yabancı anahtar tarafından tanımlanan iki bire çok ilişkiden oluşur.

Bahşiş

Aşağıdaki kod ForeignAndPrincipalKeys.cs içinde bulunabilir.

Yabancı anahtarlar

Yabancı anahtarı oluşturan özellik veya özellikler genellikle kural tarafından bulunur. Özellikler, eşleme öznitelikleri kullanılarak veya model oluşturma API'sinde ile HasForeignKey açıkça yapılandırılabilir. HasForeignKey bir lambda ifadesi ile kullanılabilir. Örneğin, tek bir özellikten oluşan yabancı anahtar için:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasForeignKey(e => e.ContainingBlogId);
}

Veya birden fazla özellikten oluşan bileşik yabancı anahtar için:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasForeignKey(e => new { e.ContainingBlogId1, e.ContainingBlogId2 });
}

Bahşiş

Model oluşturma API'sinde lambda ifadelerinin kullanılması, özellik kullanımının kod analizi ve yeniden düzenleme için kullanılabilir olmasını sağlar ve ayrıca daha fazla zincirleme yöntemde kullanılmak üzere API'ye özellik türünü sağlar.

HasForeignKey yabancı anahtar özelliğinin adı dize olarak da geçirilebilir. Örneğin, tek bir özellik için:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasForeignKey("ContainingBlogId");
}

Alternatif olarak, bileşik yabancı anahtar için:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasForeignKey("ContainingBlogId1", "ContainingBlogId2");
}

Dize kullanmak şu durumlarda kullanışlıdır:

  • Özellik veya özellikler özeldir.
  • Özellik veya özellikler varlık türünde yoktur ve gölge özellikler olarak oluşturulmalıdır.
  • Özellik adı, model oluşturma işlemine yönelik bazı girişlere göre hesaplanır veya oluşturulur.

Null değer atanamayan yabancı anahtar sütunları

İsteğe bağlı ve gerekli ilişkiler bölümünde açıklandığı gibi, yabancı anahtar özelliğinin null atanabilirliği bir ilişkinin isteğe bağlı mı yoksa gerekli mi olduğunu belirler. Ancak, null atanabilir yabancı anahtar özelliği özniteliği kullanılarak [Required] veya model derleme API'sinde çağrılarak IsRequired gerekli bir ilişki için kullanılabilir. Örneğin:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasForeignKey(e => e.BlogId)
        .IsRequired();
}

Alternatif olarak, yabancı anahtar kural tarafından bulunursa, IsRequired çağrısı HasForeignKeyolmadan kullanılabilir:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .IsRequired();
}

Bunun sonucu, yabancı anahtar özelliği null atanabilir olsa bile veritabanındaki yabancı anahtar sütununun boş değer atanamaz hale getiriliyor olmasıdır. Aynı şey, yabancı anahtar özelliğinin kendisini gerektiği gibi açıkça yapılandırarak elde edilebilir. Örneğin:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Post>()
        .Property(e => e.BlogId)
        .IsRequired();
}

Gölge yabancı anahtarlar

Yabancı anahtar özellikleri gölge özellikler olarak oluşturulabilir. EF modelinde bir gölge özellik var, ancak .NET türünde yok. EF, özellik değerini ve durumunu dahili olarak izler.

Gölge yabancı anahtarlar genellikle yabancı anahtarın ilişkisel kavramını uygulama kodu/iş mantığı tarafından kullanılan etki alanı modelinden gizleme isteği olduğunda kullanılır. Bu uygulama kodu daha sonra ilişkiyi tamamen gezintiler aracılığıyla değiştirir.

Bahşiş

Varlıklar seri hale getirilecekse, örneğin bir kablo üzerinden gönderilecekse, yabancı anahtar değerleri varlıklar bir nesne/grafik formunda olmadığında ilişki bilgilerini olduğu gibi tutmak için yararlı bir yol olabilir. Bu nedenle, bu amaç için yabancı anahtar özelliklerini .NET türünde tutmak genellikle pragmatiktir. Yabancı anahtar özellikleri özel olabilir, bu da değerinin varlıkla birlikte hareket etmelerine izin verirken yabancı anahtarı açığa çıkarmaktan kaçınmak için genellikle iyi bir risktir.

Gölge yabancı anahtar özellikleri genellikle kural tarafından oluşturulur. bağımsız değişkeni HasForeignKey herhangi bir .NET özelliğiyle eşleşmiyorsa, gölge yabancı anahtar da oluşturulur. Örneğin:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasForeignKey("MyBlogId");
}

Kurala göre, gölge yabancı anahtar türü ilişkideki asıl anahtardan alır. İlişki gerektiği gibi algılanmadığı veya yapılandırılmadığı sürece bu tür null yapılabilir hale gelir.

Gölge yabancı anahtar özelliği açıkça da oluşturulabilir. Bu özellik, özelliğin modellerini yapılandırmak için kullanışlıdır. Örneğin, özelliğini null atanamaz hale getirmek için:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Post>()
        .Property<string>("MyBlogId")
        .IsRequired();

    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasForeignKey("MyBlogId");
}

Bahşiş

Kural gereği, yabancı anahtar özellikleri ilişkideki asıl anahtardan maksimum uzunluk ve Unicode desteği gibi modelleri devralır. Bu nedenle, yabancı anahtar özelliğinde modellerin açıkça yapılandırılması nadiren gereklidir.

Verilen ad varlık türünün herhangi bir özelliğiyle eşleşmiyorsa gölge özellik oluşturma özelliği kullanılarak ConfigureWarningsdevre dışı bırakılabilir. Örneğin:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder.ConfigureWarnings(b => b.Throw(CoreEventId.ShadowPropertyCreated));

Yabancı anahtar kısıtlama adları

Kurala göre yabancı anahtar kısıtlamaları olarak adlandırılır FK_<dependent type name>_<principal type name>_<foreign key property name>. Bileşik yabancı anahtarlar için, <foreign key property name> yabancı anahtar özellik adlarının alt çizgiyle ayrılmış listesi haline gelir.

Bu, kullanılarak HasConstraintNamemodel derleme API'sinde değiştirilebilir. Örneğin:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasForeignKey(e => e.BlogId)
        .HasConstraintName("My_BlogId_Constraint");
}

Bahşiş

Kısıtlama adı EF çalışma zamanı tarafından kullanılmaz. Yalnızca EF Core Migrations kullanılarak veritabanı şeması oluşturulurken kullanılır.

Yabancı anahtarlar için dizinler

Kural gereği EF, yabancı anahtarın özelliği veya özellikleri için bir veritabanı dizini oluşturur. Kural tarafından oluşturulan dizin türleri hakkında daha fazla bilgi için bkz . Model oluşturma kuralları.

Bahşiş

EF modelinde bu modele dahil edilen varlık türleri arasındaki ilişkiler tanımlanır. Bazı ilişkilerin farklı bir bağlam modelindeki bir varlık türüne başvurması gerekebilir; örneğin, BoundedContext deseni kullanılırken. Bu durumda, yabancı anahtar sütunlarının normal özelliklere eşlenmesi gerekir ve bu özellikler ilişkideki değişiklikleri işlemek için el ile işlenebilir.

Asıl anahtarlar

Kural gereği, yabancı anahtarlar ilişkinin asıl sonundaki birincil anahtarla kısıtlanır. Ancak, bunun yerine alternatif bir anahtar kullanılabilir. Bu, model oluşturma API'sinde kullanılarak HasPrincipalKey elde edilir. Örneğin, tek bir özellik yabancı anahtarı için:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasPrincipalKey(e => e.AlternateId);
}

Veya birden çok özelliğe sahip bileşik yabancı anahtar için:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasPrincipalKey(e => new { e.AlternateId1, e.AlternateId2 });
}

HasPrincipalKey alternatif anahtar özelliğinin adı dize olarak da geçirilebilir. Örneğin, tek bir özellik anahtarı için:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasPrincipalKey("AlternateId");
}

Veya bileşik anahtar için:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasPrincipalKey("AlternateId1", "AlternateId2");
}

Dekont

Asıl ve yabancı anahtardaki özelliklerin sırası eşleşmelidir. Bu aynı zamanda anahtarın veritabanı şemasında tanımlandığı sıradır. Varlık türündeki özelliklerin sırası veya tablodaki sütunlar ile aynı olması gerekmez.

Asıl varlıkta alternatif anahtarı tanımlamak için çağrı HasAlternateKey yapılması gerekmez; bu, birincil anahtar özellikleri olmayan özelliklerle kullanıldığında otomatik HasPrincipalKey olarak yapılır. Ancak, HasAlternateKey veritabanı kısıtlama adını ayarlamak gibi alternatif anahtarı daha fazla yapılandırmak için kullanılabilir. Daha fazla bilgi için bkz . Anahtarlar .

Anahtarsız varlıklarla ilişkiler

Her ilişkinin bir sorumluya (birincil veya alternatif) başvuran bir yabancı anahtarı olmalıdır. Bu, anahtarsız varlık türünün , başvuruda bulunabilecek yabancı anahtarlar için bir asıl anahtar olmadığından ilişkinin asıl sonu olarak hareket edemeyeceği anlamına gelir.

Bahşiş

Varlık türünün alternatif anahtarı olamaz, ancak birincil anahtar yoktur. Bu durumda, alternatif anahtar (veya birkaç anahtar varsa alternatif anahtarlardan biri) birincil anahtara yükseltilmelidir.

Ancak, anahtarsız varlık türleri hala tanımlanmış yabancı anahtarlara sahip olabilir ve bu nedenle ilişkinin bağımlı sonu olarak hareket edebilir. Örneğin, Tag anahtarı olmayan şu türleri göz önünde bulundurun:

public class Tag
{
    public string Text { get; set; } = null!;
    public int PostId { get; set; }
    public Post Post { get; set; } = null!;
}

public class Post
{
    public int Id { get; set; }
}

Tag , ilişkinin bağımlı sonunda yapılandırılabilir:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Tag>()
        .HasNoKey();

    modelBuilder.Entity<Post>()
        .HasMany<Tag>()
        .WithOne(e => e.Post);
}

Dekont

EF, anahtarsız varlık türlerine işaret eden gezintileri desteklemez. Bkz. GitHub Sorunu #30331.

Çoka çok ilişkilerinde yabancı anahtarlar

Çoka çok ilişkilerde, yabancı anahtarlar birleştirme varlık türünde tanımlanır ve birleştirme tablosundaki yabancı anahtar kısıtlamalarına eşlenir. Yukarıda açıklanan her şey bu birleştirme varlığı yabancı anahtarlarına da uygulanabilir. Örneğin, veritabanı kısıtlaması adlarını ayarlama:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Post>()
        .HasMany(e => e.Tags)
        .WithMany(e => e.Posts)
        .UsingEntity(
            l => l.HasOne(typeof(Tag)).WithMany().HasConstraintName("TagForeignKey_Constraint"),
            r => r.HasOne(typeof(Post)).WithMany().HasConstraintName("PostForeignKey_Constraint"));
}