实战:处理数据(处理实体关系)

时间:2022-03-14 03:47:59

本部分描写叙述了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 authors var author = books[0].Author; // Loads the author for books[0]

当延迟载入开启时。在books[0]上訪问Author属性会使EF为author查询数据库。

延迟载入须要多段数据库操作过程。由于每次EF发送一个查询它都会取出一次相关实体。