Aracılığıyla paylaş


Varlık İlişkilerini İşleme

Tamamlanan Projeyi İndir

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şlendiğini gösteren 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..)

Hevesli Yükleme ve Gecikmeli Yükleme

EF'yi ilişkisel bir veritabanıyla kullanırken, EF'nin ilgili verileri nasıl yüklemiş olduğunu anlamak önemlidir.

EF'nin 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'nin ilgili Yazar 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.

Başvuru için, sınıftaki kitap listesini döndüren yöntem BooksController 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, yavaş yükleme ve açık yükleme. Her teknikte dengeler vardır, bu nedenle bunların nasıl çalıştığını anlamak önemlidir.

Hevesle Yükleme

İstekli 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ı yöntemini kullanın.

public IQueryable<Book> GetBooks()
{
    return db.Books
        // new code:
        .Include(b => b.Author);
}

Bu, EF'ye Author verilerini sorguya eklemesini söyler. Bu değişikliği yapıp 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'nin 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

Yavaş yüklemeyle, söz konusu varlığın gezinti özelliği başvurulduğunda EF ilgili bir 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, özelliğine Author erişim books[0] EF'nin veritabanını yazar için sorgulamasına neden olur.

Ef, ilgili varlığı her aldığında bir sorgu gönderdiği için gecikmeli yükleme birden çok veritabanı geçişi gerektirir. Genellikle, seri hale getirdiğ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 yavaş yükleme etkin kitap listesini seri hale getirdiğinde SQL sorguları aşağıda verilmiştir. EF'nin üç 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'nin çok karmaşık bir birleşim oluşturmasına neden olabilir. Veya 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ından kaçınmanın 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, koddaki 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.

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.

Sınıfına karşılık gelen gezinti özelliğini Author 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şturulur.

Book sınıfının Author sınıfını yükleyip döngüsel nesne grafı oluşturarak tam tersini gösteren diyagram.

JSON veya XML biçimlendiricisi grafı seri hale getirmeye çalıştığında bir özel durum oluşturur. İki biçimlendirici farklı özel durum iletileri oluşturur. JSON biçimlendirici 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 graf 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.