İ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 null
olmadığı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 null
ise 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ğiHashSet<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>
veyaISet<T>
olarak gösteriliyorsa, bir kullanmaReferenceEqualityComparer
örneğiHashSet<T>
oluşturulur. - Aksi takdirde, gezinti bir
IList<T>
olarak gösteriliyorsa bir örneğiList<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 , HasMany
vb. 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();
}