Aracılığıyla paylaş


İlişki gezintileri

EF Core ilişkileri yabancı anahtarlar tarafından tanımlanır. Gezintiler, ilişkileri okumak ve işlemek için doğal, nesne odaklı bir görünüm sağlamak için yabancı anahtarların üzerine katmanlıdır. Uygulamalar, gezintileri kullanarak yabancı anahtar değerlerine ne olduğuyla ilgilenmeden varlık graflarıyla çalışabilir.

Önemli

Birden çok ilişki gezintileri paylaşamaz. Herhangi bir yabancı anahtar, sorumludan bağımlıya en çok bir gezinti ve bağımlıdan sorumluya en çok bir gezinti ile ilişkilendirilebilir.

İpucu

Gecikmeli yükleme veya değişiklik izleme proxy'leri tarafından kullanılmadığı sürece gezintileri sanal hale getirmeye gerek yoktur.

Başvuru gezintileri

Gezintiler iki biçimde gelir: başvuru ve koleksiyon. Başvuru gezintileri, başka bir varlığa yapılan basit nesne başvurularıdır. Bunlar, bire çok ve bire bir ilişkilerin "bir" tarafını temsil eder. Örneğin:

public Blog TheBlog { get; set; }

Başvuru gezintilerinde ortak olması gerekmese de bir ayarlayıcı olmalıdır. Başvuru gezintileri null olmayan bir varsayılan değere otomatik olarak başlatılmamalıdır; bunu yapmak, varlığın var olmadığını onaylamaya eşdeğerdir.

C# null atanabilir başvuru türleri kullanılırken, isteğe bağlı ilişkiler için başvuru gezintilerinin null atanabilir olması gerekir:

public Blog? TheBlog { get; set; }

Gerekli ilişkiler için başvuru gezintileri null atanabilir veya null atanamaz olabilir.

Koleksiyon gezintileri

Koleksiyon gezintileri bir .NET koleksiyon türünün örnekleridir; diğer bir ifadeyle, uygulayan ICollection<T>herhangi bir tür. Koleksiyon, herhangi bir sayı içerebilen ilgili varlık türünün örneklerini içerir. Bire çok ve çoka çok ilişkilerinin "çok" tarafını temsil eder. Örneğin:

public ICollection<Post> ThePosts { get; set; }

Koleksiyon gezintilerinde ayarlayıcı olması gerekmez. Koleksiyonu satır içinde başlatmak yaygın bir durumdur ve böylece özelliğin olup nullolmadığını denetleme gereksinimi ortadan kaldırılır. Örneğin:

public ICollection<Post> ThePosts { get; } = new List<Post>();

İpucu

gibi bir ifade gövdeli özelliğini public ICollection<Post> ThePosts => new List<Post>();yanlışlıkla oluşturmayın. Bu, özelliğe her erişildiğinde yeni, boş bir koleksiyon örneği oluşturur ve bu nedenle gezinti olarak işe yaramaz.

Koleksiyon türleri

Temel alınan koleksiyon örneğinin uygulaması ICollection<T>ve bir çalışma Add yöntemine sahip olması gerekir. veya HashSet<T>yaygın olarak kullanılırList<T>. List<T> az sayıda ilgili varlık için verimlidir ve kararlı bir sıralama sağlar. HashSet<T> çok sayıda varlık için daha verimli aramalara sahiptir, ancak kararlı sıralamaya sahip değildir. Kendi özel koleksiyon uygulamanızı da kullanabilirsiniz.

Önemli

Koleksiyonun başvuru eşitliğini kullanması gerekir. Koleksiyon gezintisi için oluştururken HashSet<T> kullandığınızdan ReferenceEqualityCompareremin olun.

Uygulamalarına rağmen ICollection<T>yöntemi çağrıldığında bir özel durum oluşturması Add nedeniyle diziler koleksiyon gezintileri için kullanılamaz.

Koleksiyon örneğinin bir ICollection<T>olması gerekse de, koleksiyonun bu şekilde kullanıma sunulmaması gerekmez. Örneğin, gezintiyi uygulama kodu tarafından rastgele değiştirilemeyen salt okunur bir görünüm sağlayan bir olarak IEnumerable<T>kullanıma sunmak yaygın bir durumdur. Örneğin:

public class Blog
{
    public int Id { get; set; }
    public IEnumerable<Post> ThePosts { get; } = new List<Post>();
}

Bu desendeki bir çeşitleme, koleksiyonu gerektiği gibi işleme yöntemlerini içerir. Örneğin:

public class Blog
{
    private readonly List<Post> _posts = new();

    public int Id { get; set; }

    public IEnumerable<Post> Posts => _posts;

    public void AddPost(Post post) => _posts.Add(post);
}

Uygulama kodu yine de kullanıma sunulan koleksiyonu bir ICollection<T> öğesine yayınlayabilir ve sonra da işlenebilir. Bu bir sorunsa varlık koleksiyonun savunma kopyasını döndürebilir. Örneğin:

public class Blog
{
    private readonly List<Post> _posts = new();

    public int Id { get; set; }

    public IEnumerable<Post> Posts => _posts.ToList();

    public void AddPost(Post post) => _posts.Add(post);
}

Bundan elde edilen değerin, gezintiye her erişildiğinde koleksiyonun bir kopyasını oluşturma yükünü aşacak kadar yüksek olup olmadığını dikkatlice düşünün.

İpucu

Ef varsayılan olarak koleksiyona kendi yedekleme alanı üzerinden eriştiğinden bu son desen çalışır. Bu, EF'nin gerçek koleksiyondaki varlıkları eklediği ve kaldırdığını, uygulamaların ise koleksiyonun yalnızca savunma amaçlı bir kopyasıyla etkileşim kurduğunu gösterir.

Koleksiyon gezintilerini başlatma

Koleksiyon gezintileri, varlık türü tarafından hevesle başlatılabilir:

public class Blog
{
    public ICollection<Post> Posts { get; } = new List<Post>();
}

Alternatif olarak:

public class Blog
{
    private ICollection<Post>? _posts;

    public ICollection<Post> Posts => _posts ??= new List<Post>();
}

ÖRNEĞIN, bir sorgu yürütülürken EF'nin koleksiyon gezintisine varlık eklemesi gerekiyorsa, şu anda nullise koleksiyonu başlatır. Oluşturulan örnek, gezintinin kullanıma sunulan türüne bağlıdır.

  • Gezinti bir HashSet<T>olarak gösteriliyorsa, bir kullanma ReferenceEqualityComparer örneği HashSet<T> oluşturulur.
  • Aksi takdirde, gezinti parametresiz bir oluşturucu ile somut bir tür olarak kullanıma sunulursa, bu somut türün bir örneği oluşturulur. Bu, için List<T>geçerlidir, ancak özel koleksiyon türleri de dahil olmak üzere diğer koleksiyon türleri için de geçerlidir.
  • Aksi takdirde, gezinti bir IEnumerable<T>, ICollection<T>veya ISet<T>olarak gösteriliyorsa, bir kullanma ReferenceEqualityComparer örneği HashSet<T> oluşturulur.
  • Aksi takdirde, gezinti bir IList<T>olarak gösteriliyorsa bir örneği List<T> oluşturulur.
  • Aksi takdirde, bir özel durum oluşturulur.

Not

Değişiklik izleme proxy'leri de dahil olmak üzere bildirim varlıkları kullanılıyorsa ObservableCollection<T>ve ObservableHashSet<T> yerine List<T> ve HashSet<T>kullanılır.

Önemli

Değişiklik izleme belgelerinde açıklandığı gibi EF, belirli bir anahtar değerine sahip herhangi bir varlığın yalnızca tek bir örneğini izler. Bu, gezinti olarak kullanılan koleksiyonların başvuru eşitliği semantiğini kullanması gerektiği anlamına gelir. Nesne eşitliğini geçersiz kılmayen varlık türleri bunu varsayılan olarak alır. Tüm varlık türlerinde çalıştığından emin olmak için gezinti olarak kullanmak üzere oluştururken HashSet<T> kullandığınızdan ReferenceEqualityComparer emin olun.

Gezintileri yapılandırma

Gezintiler, ilişki yapılandırmanın bir parçası olarak modele dahil edilir. Yani, kural gereği veya model oluşturma API'sinde , HasManyvb. kullanılırHasOne. Gezintilerle ilişkili yapılandırmaların çoğu, ilişkinin kendisi yapılandırılarak gerçekleştirilir.

Ancak, genel ilişki yapılandırmasının bir parçası olmak yerine gezinti özelliklerine özgü bazı yapılandırma türleri vardır. Bu tür bir yapılandırma yöntemiyle Navigation yapılır. Örneğin, EF'yi yedekleme alanını kullanmak yerine özelliği aracılığıyla gezintiye erişmeye zorlamak için:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .Navigation(e => e.Posts)
        .UsePropertyAccessMode(PropertyAccessMode.Property);

    modelBuilder.Entity<Post>()
        .Navigation(e => e.Blog)
        .UsePropertyAccessMode(PropertyAccessMode.Property);
}

Not

Arama Navigation , gezinti özelliği oluşturmak için kullanılamaz. Yalnızca daha önce ilişki tanımlanarak veya bir kuraldan oluşturulmuş bir gezinti özelliğini yapılandırmak için kullanılır.

Gerekli gezintiler

İlişki gerekliyse bağımlıdan sorumluya bir gezinti gerekir; bu da yabancı anahtar özelliğinin null atanamaz olduğu anlamına gelir. Buna karşılık, yabancı anahtar null atanabilirse gezinti isteğe bağlıdır ve bu nedenle ilişki isteğe bağlıdır.

Sorumludan bağımlıya başvuru gezintileri farklıdır. Çoğu durumda, bir asıl varlık her zaman bağımlı varlıklar olmadan var olabilir. Başka bir ifadeyle, gerekli bir ilişki her zaman en az bir bağımlı varlık olacağını göstermez. EF modelinde hiçbir yol yoktur ve ayrıca bir sorumlunun belirli sayıda bağımlıyla ilişkilendirildiğinden emin olmak için ilişkisel veritabanında standart bir yol yoktur. Bu gerekiyorsa, uygulama (iş) mantığında uygulanmalıdır.

Sorumlu ve bağımlı türler ilişkisel veritabanında aynı tabloyu paylaştığında veya bir belgede bulunduğunda, bu kuralın tek bir özel durumu vardır. Bu, sahip olunan türlerde veya aynı tabloyu paylaşan sahip olunmayan türlerde gerçekleşebilir. Bu durumda, sorumludan bağımlıya gezinti özelliği gerekli olarak işaretlenebilir ve bu da bağımlının mevcut olması gerektiğini gösterir.

Gezinti özelliğinin gerektiği gibi yapılandırılması yöntemi kullanılarak Navigation yapılır. Örnek:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .Navigation(e => e.BlogHeader)
        .IsRequired();
}