谈谈EntityFramework Core中的异步编程及约定
约定
由于 Entity Framwork 有一定的约束条件,你只需要按规则编写很少的代码就能够创建一个完整的数据库。
-
DbSet
类型的属性用作表名。 如果实体未被DbSet
属性引用,实体类名称用作表名称。 -
使用实体属性名作为列名。
-
以 ID 或 classnameID 命名的实体属性被视为主键属性。
-
如果属性名为 <导航属性名><主键属性名>(例如,
StudentID
对应Student
导航属性,因为Student
实体的主键是ID
),其将被解释为外键属性。 此外还可以将外键属性仅命名为 <主键属性名>(例如EnrollmentID
,因为Enrollment
实体的主键为EnrollmentID
) 。
为了更好理解,我们看如下例子,建立一个Students实体
using System;
using System.Collections.Generic;
namespace ContosoUniversity.Models
{
public class Student
{
public int ID { get; set; }
public string LastName { get; set; }
public string FirstMidName { get; set; }
public DateTime EnrollmentDate { get; set; }
public ICollection<Enrollment> Enrollments { get; set; }
}
}
其中,实体属性ID,Lastanme等就是列名,ID
属性将成为对应于此类的数据库表中的主键。 默认情况下,EF 将会将名为 ID
或 classnameID
的属性解析为主键。
Enrollments
属性是导航属性。 导航属性中包含与此实体相关的其他实体。 在这个案例下,Student entity
中的 Enrollments
属性会保留所有与 Student
实体相关的 Enrollment
。 换而言之,如果在数据库中有两行描述同一个学生的修读情况 (两行的 StudentID 值相同,而且 StudentID 作为外键和某位学生的主键值相同), Student
实体的 Enrollments
导航属性将包含那两个 Enrollment
实体。
如果导航属性可以具有多个实体 (如多对多或一对多关系),那么导航属性的类型必须是可以添加、 删除和更新条目的容器,如 ICollection<T>
。 你可以指定 ICollection<T>
或实现该接口类型,如 List<T>
或 HashSet<T>
。 如果指定 ICollection<T>
,EF在默认情况下创建 HashSet<T>
集合。
数据库中的情况;
EF Core会自动将标识出导航属性
异步代码
异步编程是 ASP.NET Core 和 EF Core 的默认模式。
Web 服务器的可用线程是有限的,而在高负载情况下的可能所有线程都被占用。 当发生这种情况的时候,服务器就无法处理新请求,直到线程被释放。 使用同步代码时,可能会出现多个线程被占用但不能执行任何操作的情况,因为它们正在等待 I/O 完成。 使用异步代码时,当进程正在等待 I/O 完成,服务器可以将其线程释放用于处理其他请求。 因此,异步代码使得服务器更有效地使用资源,并且该服务器可以无延迟地处理更多流量。
异步代码在运行时,会引入的少量开销,在低流量时对性能的影响可以忽略不计,但在针对高流量情况下潜在的性能提升是可观的。
在以下代码中,async
关键字、Task<T>
返回值、await
关键字和 ToListAsync
方法让代码异步执行。
public async Task<IActionResult> Index()
{
return View(await _context.Students.ToListAsync());
}
-
async
关键字用于告知编译器该方法主体将生成回调并自动创建Task<IActionResult>
返回对象。 -
返回类型
Task<IActionResult>
表示正在进行的工作返回的结果为IActionResult
类型。 -
await
关键字会使得编译器将方法拆分为两个部分。 第一部分是以异步方式结束已启动的操作。 第二部分是当操作完成时注入调用回调方法的地方。 -
ToListAsync
是ToList
方法的的异步扩展版本。
使用 Entity Framework 编写异步代码时的一些注意事项:
-
只有导致查询或发送数据库命令的语句才能以异步方式执行。 包括
ToListAsync
,SingleOrDefaultAsync
,和SaveChangesAsync
。 不包括只需更改IQueryable
的语句,如var students = context.Students.Where(s => s.LastName == "Davolio")
。一下只返回有一个view,不需要异步方式。 -
public ActionResult Create() { var newModel = new AlbumCreateViewModel(); return View(newModel); }
-
EF 上下文是线程不安全的: 请勿尝试并行执行多个操作。 当调用异步 EF 方法时,始终使用
await
关键字。 -
如果你想要利用异步代码的性能优势,请确保你所使用的任何库和包在它们调用导致 Entity Framework 数据库查询方法时也使用异步。
有关在 .NET 异步编程的详细信息,请参阅 异步概述。