【Web API系列教程】3.4 — 實戰:處理資料(處理實體關聯)

來源:互聯網
上載者:User

標籤:self   content   異常   string   asm   過程   名稱   產生   rac   

前言

本部分描寫敘述了EF怎樣載入相關實體的細節,而且怎樣在你的模型類中處理環形導覽屬性。(本部分預備了背景知識,而這不是完畢這個教程所必須的。你也能夠跳到第五節)

預載入和延遲載入

預載入和延遲載入的英文名稱各自是Eager Loading和Lazy Loading。

當EF與關聯式資料庫一同使用時。瞭解EF是怎樣載入相關資料是很重要的。

去查看EF產生的SQL查詢也是很有協助的。

為了追蹤SQL,加入下列代碼到BookServiceContext構造器中:

public BookServiceContext() : base("name=BookServiceContext"){    // New code:    this.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);}

假設發送一個GET請求到/api/books,它返回像以下這種JSON:

[  {    "BookId": 1,    "Title": "Pride and Prejudice",    "Year": 1813,    "Price": 9.99,    "Genre": "Comedy of manners",    "AuthorId": 1,    "Author": null  },  ...

你能看到Author屬性是空的,即便book包括有效AuthorId。

那是由於EF沒有在載入相關的Author實體。關於SQL查詢的追蹤記錄檔例如以下:

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]

該SQL跟蹤在Visual Studio的Output表單中顯示。——譯者注

SELECT語句從Books表中擷取資料,但並沒有引用Author表。
作為參考,這裡是在BooksController類中的方法。它返回books的列表。

public IQueryable<Book> GetBooks(){    return db.Books;}

來看看我們怎樣才幹讓Author作為返回的JSON資料的一部分。在Entity Framework中有三種方式載入相關資料:預載入(eager loading)、延遲載入(lazy loading)和顯式載入(explicit loading)。我們應該在這三種技術中有所取捨,所以瞭解它們是怎樣工作的就很重要了。

Eager Loading(預載入)

在預載入中,EF載入相關資料作為初始化資料庫查詢的一部分。

為了運行預載入,使用System.Data.Entity.Include擴充方法。

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

這會告訴EF將Author資料包括在查詢中。假設你做了這個改變並運行了app。如今JSON資料會是例如以下所看到的:

[  {    "BookId": 1,    "Title": "Pride and Prejudice",    "Year": 1813,    "Price": 9.99,    "Genre": "Comedy of manners",    "AuthorId": 1,    "Author": {      "AuthorId": 1,      "Name": "Jane Austen"    }  },  ...

其追蹤記錄檔顯示EF在Book和Author表中運行了一個join操作。

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]
Lazy Loading(延遲載入)

在延遲載入中,當實體的導覽屬性是非關聯時,EF會自己主動載入一個相關的實體。為了使用延遲載入。使導覽屬性變成虛擬。

比如。在Book類中:

public class Book{    // (Other properties)    // Virtual navigation property    public virtual Author Author { get; set; }}

如今考慮例如以下代碼:

var books = db.Books.ToList();  // Does not load authorsvar author = books[0].Author;   // Loads the author for books[0]

當延遲載入開啟時。在books[0]上訪問Author屬性會使EF為author查詢資料庫。

延遲載入須要多段資料庫操作過程。由於每次EF發送一個查詢它都會取出一次相關實體。

通常。你希望為序列化的對象禁用延遲載入。序列化已經在模型上讀取了全部可能觸發載入相關實體的屬性。比如,以下是當延遲載入開啟後EF序列化books列表時的SQL查詢。

你能夠看到EF對於三個作者做了三次不同的查詢。

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] = @EntityKeyValue1SELECT     [Extent1].[AuthorId] AS [AuthorId],     [Extent1].[Name] AS [Name]    FROM [dbo].[Authors] AS [Extent1]    WHERE [Extent1].[AuthorId] = @EntityKeyValue1SELECT     [Extent1].[AuthorId] AS [AuthorId],     [Extent1].[Name] AS [Name]    FROM [dbo].[Authors] AS [Extent1]    WHERE [Extent1].[AuthorId] = @EntityKeyValue1

但還有很多時候你可能想要使用延遲載入。

預載入會造成EF產生很複雜的聯結。或者你可能須要對於小的資料集合的相關實體。延遲載入會更加有效。

避免序列化問題的一種方式是序列化傳輸資料對象(DTOs)而不是實體物件。我將會在後面的文章中展示這種實現。

顯式載入(Explicit Loading)

顯式載入和延遲載入很相似,除了你在代碼中顯式地擷取相關資料;當你訪問導覽屬性時它不會自己主動發生。

顯示載入會在載入相關資料時給你很多其它的控制權,但也須要額外的代碼。關於顯示載入的很多其它資訊,請查看Loading Related Entities。

http://msdn.microsoft.com/en-us/data/jj574232#explicit

導覽屬性和環形引用(Navigation Properties and Circular References)

當我定義Book和Author模型時。我在Book類中為Book-Author關係定義了導覽屬性。但我沒有在其它方向定義導覽屬性。

假設你在Author類中也定義對應的導覽屬性會怎樣呢?

public class Author{    public int AuthorId { get; set; }    [Required]    public string Name { get; set; }    public ICollection<Book> Books { get; set; }}

不幸的是。當你在序列化模型時這會產生一個問題。

假設你載入相關資料,它會產生環形對象圖。

當JSON或XML格式試圖序列化圖時。它將會拋出一個異常。

這兩個格式拋出不同異常資訊。這裡是JSON格式的示範範例:

{  "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格式的示範範例:

<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>

一個解決方式是使用DTO,我將會在下一節中描寫敘述它。

你能夠配置JSON或XML格式化程式來處理圖迴圈。關於很多其它資訊,請查看Handling Circular Object References. (http://www.asp.net/web-api/overview/formats-and-model-binding/json-and-xml-serialization#handling_circular_object_references)

對於本教程。你不須要Author.Book導航熟悉,所以你能夠去掉它。

【Web API系列教程】3.4 — 實戰:處理資料(處理實體關聯)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.