[Web API series tutorial] 3.4-practice: process data (process Object Relationships)

Source: Internet
Author: User

[Web API series tutorial] 3.4-practice: process data (process Object Relationships)
Preface

This section describes how EF loads the details of related entities and how to process ring navigation attributes in your model class. (This section provides background knowledge, which is not necessary to complete this tutorial. You can also skip to section 5)

Pre-loading and delayed Loading

The names of preload and delayed load are Eager Loading and Lazy Loading.

When EF is used together with relational databases, it is very important to know how EF loads relevant data.

It is also helpful to view the SQL query generated by EF. To track SQL, add the following code to the BookServiceContext constructor:

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

If you send a GET request to/api/books, it returns JSON like the following:

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

You can see that the Author attribute is empty, even if the book contains a valid AuthorId. That is because EF is not loading the relevant Author entity. The SQL query trace log is as follows:

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]

The SQL trace is displayed in the Output window of Visual Studio. -- Translator's note

The SELECT statement retrieves data from the Books table, but does not reference the Author table.
For reference, here is the method in the BooksController class, which returns the list of books.

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

Let's see how we can make Author a part of the returned JSON data. There are three ways to load related data in Entity Framework: eager loading, lazy loading, and explicit loading ). We should make a choice among these three technologies, so it is very important to understand how they work.

Eager Loading (pre-Loading)

In the pre-loading process, EF loads related data as part of initializing database queries. To perform the pre-loading, use the System. Data. Entity. Include extension method.

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

This tells EF to include Author data in the query. If you make this change and run the app, The JSON data is as follows:

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

The tracing log shows that EF performs a join operation in the Book and Author tables.

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)

In delayed loading, when the navigation attribute of an object is not associated, EF automatically loads a related object. To use delayed loading, make the navigation attribute virtual. For example, in the Book class:

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

Consider the following code:

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

When delayed loading is enabled, accessing the Author attribute on books [0] will enable EF to query the database for author.

The multi-segment database operation process is required for delayed loading, because each time EF sends a query, it will retrieve the relevant entities. Generally, you want to disable delayed loading for serialized objects. Serialization has read all attributes that may trigger loading of related entities on the model. For example, the following is an SQL query when the EF serialization books list is enabled after delayed loading. You can see that EF has made three different queries for the three authors.

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

However, you may also want to use delayed loading. Pre-loading may cause EF to generate very complex connections. Or you may need to delay loading more effectively for the entities related to small data sets.

One way to avoid serialization problems is to serialize the data transmission object (DTOs) instead of the object. I will show this implementation in a later article.

Explicit Loading)

Explicit loading is similar to delayed loading, except that you explicitly obtain the relevant data in the code. It does not automatically occur when you access the navigation attribute. It shows that loading gives you more control when loading the relevant data, but requires additional code. For more information about Loading, see Loading Related Entities.

Navigation Properties and Circular References)

When I define the Book and Author models, I defined navigation properties for the Book-Author Relationship in the Book class, but I did not define navigation properties in other directions.

What if you define the corresponding navigation attributes in the Author class?

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

Unfortunately, this will cause a problem when you serialize the model. If you load the relevant data, it will generate a circular object graph.

When trying to serialize a graph in JSON or XML format, it throws an exception. The two formats throw different exception information. Here is an example of JSON format:

{  "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": "...”     }}

Here is an example of XML format:

<code class=" hljs 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></stacktrace></error></code>

A solution is to use DTO, which I will describe in the next section. You can configure JSON or XML formatting programs to process graph loops. For more information, see Handling Circular Object References. (http://www.asp.net/web-api/overview/formats-and-model-binding/json-and-xml-serialization)

For this tutorial, you do not need to be familiar with the Author. Book navigation, so you can remove it.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

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.