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.
Bu bölümde EF'nin ilgili varlıkları nasıl yüklediği ve model sınıflarınızda döngüsel gezinti özelliklerinin nasıl işleneceğinin bazı ayrıntıları açıklanmaktadır. (Bu bölüm arka plan bilgisi sağlar ve öğreticiyi tamamlamak için gerekli değildir. İsterseniz Bölüm 5'e atlayın..)
Eager Yükleme ve Gecikmeli Yükleme karşılaştırması
EF'yi ilişkisel veritabanıyla kullanırken, EF'nin ilgili verileri nasıl yüklediğinden anlamak önemlidir.
EF'in oluşturduğu SQL sorgularını görmek de yararlıdır. SQL'i izlemek için oluşturucuya BookServiceContext aşağıdaki kod satırını ekleyin:
public BookServiceContext() : base("name=BookServiceContext")
{
// New code:
this.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
}
/api/books adresine bir GET isteği gönderirseniz, aşağıdaki gibi JSON döndürür:
[
{
"BookId": 1,
"Title": "Pride and Prejudice",
"Year": 1813,
"Price": 9.99,
"Genre": "Comedy of manners",
"AuthorId": 1,
"Author": null
},
...
Kitabın geçerli bir AuthorId içermesine rağmen Author özelliğinin null olduğunu görebilirsiniz. Bunun nedeni EF'in ilgili Author varlıklarını yüklememesidir. SQL sorgusunun izleme günlüğü bunu onaylar:
SELECT
[Extent1].[BookId] AS [BookId],
[Extent1].[Title] AS [Title],
[Extent1].[Year] AS [Year],
[Extent1].[Price] AS [Price],
[Extent1].[Genre] AS [Genre],
[Extent1].[AuthorId] AS [AuthorId]
FROM [dbo].[Books] AS [Extent1]
SELECT deyimi Kitaplar tablosundan alır ve Yazar tablosuna başvurmaz.
Referans olarak, BooksController sınıfındaki kitap listesini döndüren yöntem aşağıdadır.
public IQueryable<Book> GetBooks()
{
return db.Books;
}
JSON verilerinin bir parçası olarak Yazar'ı nasıl döndürebileceğimizi görelim. Entity Framework'te ilgili verileri yüklemenin üç yolu vardır: istekli yükleme, gecikmeli yükleme ve açık yükleme. Her teknikte dengeler vardır, bu nedenle nasıl çalıştıklarını anlamak önemlidir.
Eager Loading
Hızlı yükleme ile EF, ilk veritabanı sorgusunun bir parçası olarak ilgili varlıkları yükler. İstekli yükleme gerçekleştirmek için System.Data.Entity.Include uzantısı yöntemini kullanın.
public IQueryable<Book> GetBooks()
{
return db.Books
// new code:
.Include(b => b.Author);
}
Bu, EF'e Sorguya Yazar verilerini eklemesini söyler. Bu değişikliği yaparsanız ve uygulamayı çalıştırırsanız, JSON verileri şu şekilde görünür:
[
{
"BookId": 1,
"Title": "Pride and Prejudice",
"Year": 1813,
"Price": 9.99,
"Genre": "Comedy of manners",
"AuthorId": 1,
"Author": {
"AuthorId": 1,
"Name": "Jane Austen"
}
},
...
İzleme günlüğü, EF'in Kitap ve Yazar tablolarında birleştirme gerçekleştirdiğini gösterir.
SELECT
[Extent1].[BookId] AS [BookId],
[Extent1].[Title] AS [Title],
[Extent1].[Year] AS [Year],
[Extent1].[Price] AS [Price],
[Extent1].[Genre] AS [Genre],
[Extent1].[AuthorId] AS [AuthorId],
[Extent2].[AuthorId] AS [AuthorId1],
[Extent2].[Name] AS [Name]
FROM [dbo].[Books] AS [Extent1]
INNER JOIN [dbo].[Authors] AS [Extent2] ON [Extent1].[AuthorId] = [Extent2].[AuthorId]
Gecikmeli Yükleme
Gecikmeli yükleme ile, EF gezinti özelliğine başvurulduğunda ilgili varlığı otomatik olarak yükler. Yavaş yüklemeyi etkinleştirmek için gezinti özelliğini sanal hale getirin. Örneğin, Book sınıfında:
public class Book
{
// (Other properties)
// Virtual navigation property
public virtual Author Author { get; set; }
}
Şimdi aşağıdaki kodu göz önünde bulundurun:
var books = db.Books.ToList(); // Does not load authors
var author = books[0].Author; // Loads the author for books[0]
Gecikmeli yükleme etkinleştirildiğinde, Author özelliğine erişim, books[0] EF'nin veritabanını yazar için sorgulamasına neden olur.
EF, ilgili bir varlığı her aldığında bir sorgu gönderdiği için gecikmeli yükleme birden çok veritabanı gezisi gerektirir. Genellikle, serileştirdiğiniz nesneler için gecikmeli yüklemenin devre dışı bırakılmasını istersiniz. Seri hale getiricinin modeldeki tüm özellikleri okuması gerekir ve bu da ilgili varlıkların yüklenmesini tetikler. Örneğin, EF'in yavaş yükleme etkin olduğunda kitap listesini seri hale getirdiğinde ortaya çıkan SQL sorguları aşağıda verilmiştir. EF'in üç yazar için üç ayrı sorgu yaptığını görebilirsiniz.
SELECT
[Extent1].[BookId] AS [BookId],
[Extent1].[Title] AS [Title],
[Extent1].[Year] AS [Year],
[Extent1].[Price] AS [Price],
[Extent1].[Genre] AS [Genre],
[Extent1].[AuthorId] AS [AuthorId]
FROM [dbo].[Books] AS [Extent1]
SELECT
[Extent1].[AuthorId] AS [AuthorId],
[Extent1].[Name] AS [Name]
FROM [dbo].[Authors] AS [Extent1]
WHERE [Extent1].[AuthorId] = @EntityKeyValue1
SELECT
[Extent1].[AuthorId] AS [AuthorId],
[Extent1].[Name] AS [Name]
FROM [dbo].[Authors] AS [Extent1]
WHERE [Extent1].[AuthorId] = @EntityKeyValue1
SELECT
[Extent1].[AuthorId] AS [AuthorId],
[Extent1].[Name] AS [Name]
FROM [dbo].[Authors] AS [Extent1]
WHERE [Extent1].[AuthorId] = @EntityKeyValue1
Hala gecikmeli yükleme kullanmak isteyebileceğiniz zamanlar vardır. İstekli yükleme EF'in çok karmaşık bir birleşim oluşturmasına neden olabilir. Ya da verilerin küçük bir alt kümesi için ilgili varlıklara ihtiyacınız olabilir ve gecikmeli yükleme daha verimli olabilir.
Serileştirme sorunlarını önlemenin bir yolu, varlık nesneleri yerine veri aktarım nesnelerini (DTO) seri hale getirmektir. Bu yaklaşımı makalenin ilerleyen bölümlerinde göstereceğim.
Açık Yükleme
Açık yükleme, kodda ilgili verileri açıkça almanız dışında gecikmeli yüklemeye benzer; bir gezinti özelliğine eriştiğinde otomatik olarak gerçekleşmez. Açık yükleme, ilgili verilerin ne zaman yüklendiği üzerinde daha fazla denetim sağlar, ancak ek kod gerektirir. Açık yükleme hakkında daha fazla bilgi için bkz . İlgili Varlıkları Yükleme.
Gezinme Özellikleri ve Döngüsel Referanslar
Kitap ve Yazar modellerini tanımladığımda, Book-Author ilişkisi için sınıfında bir gezinti özelliği Book tanımladım, ancak diğer yönde bir gezinti özelliği tanımlamadım.
Author sınıfına karşılık gelen gezinti özelliğini eklerseniz ne olur?
public class Author
{
public int AuthorId { get; set; }
[Required]
public string Name { get; set; }
public ICollection<Book> Books { get; set; }
}
Ne yazık ki bu, modelleri seri hale getirdiğinizde bir sorun oluşturur. İlgili verileri yüklerseniz, döngüsel bir nesne grafı oluşturur.
JSON veya XML biçimlendiricisi grafiği seri hale getirmeye çalıştığında bir özel durum oluşturur. İki biçimlendirici farklı özel durum iletileri oluşturur. JSON biçimlendiricisi için bir örnek aşağıda verilmiştir:
{
"Message": "An error has occurred.",
"ExceptionMessage": "The 'ObjectContent`1' type failed to serialize the response body for content type
'application/json; charset=utf-8'.",
"ExceptionType": "System.InvalidOperationException",
"StackTrace": null,
"InnerException": {
"Message": "An error has occurred.",
"ExceptionMessage": "Self referencing loop detected with type 'BookService.Models.Book'.
Path '[0].Author.Books'.",
"ExceptionType": "Newtonsoft.Json.JsonSerializationException",
"StackTrace": "..."
}
}
XML biçimlendiricisi aşağıdadır:
<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>The 'ObjectContent`1' type failed to serialize the response body for content type
'application/xml; charset=utf-8'.</ExceptionMessage>
<ExceptionType>System.InvalidOperationException</ExceptionType>
<StackTrace />
<InnerException>
<Message>An error has occurred.</Message>
<ExceptionMessage>Object graph for type 'BookService.Models.Author' contains cycles and cannot be
serialized if reference tracking is disabled.</ExceptionMessage>
<ExceptionType>System.Runtime.Serialization.SerializationException</ExceptionType>
<StackTrace> ... </StackTrace>
</InnerException>
</Error>
Çözümlerden biri, sonraki bölümde açıkladığım DTO'ları kullanmaktır. Alternatif olarak, JSON ve XML biçimlendiricilerini grafik döngülerini işleyecek şekilde yapılandırabilirsiniz. Daha fazla bilgi için bkz. Döngüsel Nesne Başvurularını İşleme.
Bu öğreticide gezinti özelliğine Author.Book ihtiyacınız yoktur, bu nedenle bu özelliği dışarıda bırakabilirsiniz.