Preface
This section describes how EF loads the details of the related entities and how to handle the ring navigation properties in your model class. (This section prepares background knowledge, which is not required to complete this tutorial.) You can also jump to the fifth quarter)
pre-loading and delay loading
Pre-loaded and delayed loading English names are eager Loading and lazy Loading respectively.
When EF is used in conjunction with a relational database. It is important to understand how EF is loading relevant data.
It is also helpful to look at the SQL queries generated by EF.
To trace 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);}
Assuming a GET request is sent 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 property is empty, even if the book includes a valid Authorid.
That is because EF is not loading the associated author entity. trace logs about SQL queries such as the following:
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 form of Visual Studio. --Translator's note
The SELECT statement obtains data from the books table, but does not reference the author table.
As a reference, here is the method in the Bookscontroller class. It returns a list of books.
publicGetBooks(){ return db.Books;}
Let's see how we can make author as part of the JSON data returned. There are three ways to load related data in the Entity Framework: preload (eager loading), deferred load (lazy loading), and explicit loading (explicit loading). We should choose between these three technologies, so it's important to understand how they work.
Eager Loading (pre-loaded)
In preload, EF loads the relevant data as part of the initialization database query.
To run preload, use the System.Data.Entity.Include extension method.
publicGetBooks(){ return db.Books // new code: .Include(b => b.Author);}
This tells EF to include the author data in the query. Let's say you've made this change and run the app. Now the JSON data will look like the following:
[ { "BookId":1, "Title":"Pride and Prejudice", " Year":1813, " Price":9.99, "Genre":"Comedy of Manners", "Authorid":1, "Author":{"authorid": 1, "Name": "Jane Austen" }}, ...
Its trace log shows that EF runs 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 (delayed loading)
In deferred loading, when the navigation properties of an entity are non-associative, EF will voluntarily load a related entity itself. In order to use deferred loading. Make the navigation property virtual.
Like what. In the Book Class:
publicclass Book{ // (Other properties) // Virtual navigation property publicvirtualgetset; }}
Now consider the following code, for example:
var books = db.Books.ToList(); // Does not load authorsvar author = books[0].Author; // Loads the author for books[0]
When delay loading is turned on. Visiting the author property on Books[0] causes EF to query the database for author.
Delay loading requires a multi-stage database operation process. Because each time the EF sends a query, it takes out the related entity one time.
Usually. You want to disable lazy loading for the serialized object. Serialization has read all the properties on the model that could trigger the loading of related entities. For example, the following is the SQL query when the EF serializes the books list after a delay load is turned on.
You can see that EF has made three different queries for 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
But there are a lot of times when you might want to use lazy loading.
Pre-loading leads to a complex join of EF generation. Or you might need a related entity for a small collection of data. Delayed onboarding is more effective.
One way to avoid serializing problems is to serialize the transport data object (DTOS) instead of the entity object. I will show this implementation in a later article.
Explicit loading (Explicit Loading)
Explicit loading and lazy loading are similar, except that you explicitly get the relevant data in your code, and it does not take its own initiative when you access the navigation properties.
Shows that the onboarding will give you a lot of other control when loading the relevant data, but it also requires additional code. See loading related entities for a lot of other information about displaying loading.
Http://msdn.microsoft.com/en-us/data/jj574232#explicit
Navigation properties and ring references (Navigation properties and Circular References)
When I define the book and the author model. I defined the navigation properties for the Book-author relationship in the book class. But I didn't define the navigation properties in any other direction.
What if you also define the corresponding navigation property in the author class?
publicclass Author{ publicintgetset; } [Required] publicstringgetset; } publicgetset; }}
Unfortunately, it is. This creates a problem when you serialize the model.
Assuming you load the relevant data, it produces a circular object graph.
When the JSON or XML format attempts to serialize a diagram. It will throw an exception.
These two formats throw different exception information. Here is a demo sample in 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 a demo in XML format:
<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 being serialized if reference tracking is Disabled.</exceptionmessage> <exceptiontype>System.Runtime.Serialization.SerializationException</exceptiontype> <StackTrace>...</StackTrace> </innerexception></Error>
One solution is to use a dto, and I'll describe it in the next section.
You can configure the JSON or XML formatter to handle graph loops. For a lot of other information, see Handling Circular Object References. (Http://www.asp.net/web-api/overview/formats-and-model-binding/json-and-xml-serialization#handling_circular_ Object_references)
For this tutorial. You don't need to be familiar with Author.book navigation, so you can get rid of it.
Web API Series Tutorial 3.4-Combat: Working with data (working with entity relationships)