EF Core 2.0中如何手动映射数据库的视图为实体
Posted opencoder
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了EF Core 2.0中如何手动映射数据库的视图为实体相关的知识,希望对你有一定的参考价值。
由于Scaffold-DbContext指令目前还不支持自动映射数据库中的视图为实体,所以当我们想使用EF Core来读取数据库视图数据的时候,我们需要手动去做映射,本文介绍如何在EF Core中手动映射数据库的视图为实体。
假设我们在SQL Server中有如下数据库视图[dbo].[V_Person]:
CREATE VIEW [dbo].[V_Person] AS SELECT ID, Code, Name, CreateTime, UpdateTime FROM dbo.Person GO
其结构如下,共有五列数据:
在EF Core中映射数据库视图有一个硬条件,那就是视图中必须有一列要拥有唯一值,而如果你的视图中没有唯一列请在视图中构造一个唯一列(可以参考这个链接的文章)。这是因为EF Core要求每一个实体要拥有唯一属性(Key),而既然我们要把数据库视图映射为EF Core的实体,那么视图就要求必须有一个唯一列。
本例中数据库视图V_Person的列ID是唯一的。
首先我们定义一个实体类V_Person,用来映射数据库视图V_Person,其属性和数据库视图V_Person的列一一对应:
using System; namespace FFCoreView.Entities { /// <summary> /// 定义实体V_Person,其结构和数据库视图V_Person相同 /// </summary> public class V_Person { public int Id { get; set; } public string Code { get; set; } public string Name { get; set; } public DateTime? CreateTime { get; set; } public DateTime? UpdateTime { get; set; } } }
然后我们来构造一个自定义的DbContext类TestDbExContext,其继承于Scaffold-DbContext指令自动生成的DbContext类TestDBContext:
using FFCoreView.Entities; using Microsoft.EntityFrameworkCore; namespace FFCoreView.Extension { /// <summary> /// TestDbExContext继承TestDBContext,而TestDBContext又继承DbContext /// </summary> public class TestDbExContext : TestDBContext { /// <summary> /// 定义一个DbSet<V_Person>的集合属性V_Person,EF Core会自动为其赋值,然后可以利用TestDbExContext.V_Person属性来读取数据库中V_Person视图的数据 /// </summary> public virtual DbSet<V_Person> V_Person { get; set; } /// <summary> /// 在重写的OnModelCreating方法中,使用Fluent API来设置实体V_Person和数据库中V_Person视图的关系 /// </summary> protected override void OnModelCreating(ModelBuilder modelBuilder) { //先调用基类的OnModelCreating方法,设置数据库中其它表和实体的映射关系 base.OnModelCreating(modelBuilder); //接着设置实体V_Person和数据库中V_Person视图的关系 modelBuilder.Entity<V_Person>(entity => { //告诉EF Core实体V_Person对应数据库中的V_Person视图,这里使用entity.ToTable方法后,上面的DbSet<V_Person> V_Person集合属性可以叫任何名字,比如我们可以将其定义为DbSet<V_Person> V_People也可以,如果不使用entity.ToTable方法,那么DbSet<V_Person> V_Person的属性名字必须和数据库视图V_Person的名字相同,否则EF Core会报错 entity.ToTable("V_Person"); //设置实体的唯一属性,因为我们知道数据库中V_Person视图的ID列值是唯一的,所以这里我们设置实体V_Person的Id属性为唯一属性 entity.HasKey(e => e.Id); //利用Fluent API将实体V_Person的每一列映射到数据库视图的每一列 entity.Property(e => e.Id).HasColumnName("ID"); entity.Property(e => e.Code).HasColumnName("Code"); entity.Property(e => e.Name).HasColumnName("Name"); entity.Property(e => e.CreateTime).HasColumnName("CreateTime"); entity.Property(e => e.UpdateTime).HasColumnName("UpdateTime"); }); } } }
在我们自定义的TestDbExContext类中,我们定义了个DbSet<V_Person> V_Person集合属性,EF Core会为我们自动为其赋值,我们可以使用这个集合属性来读取数据库视图V_Person的所有数据,然后重写了DbContext的OnModelCreating方法,使用Fluent API来设置了实体V_Person和数据库中V_Person视图的关系。
然后我们在.NET Core控制台项目的Program类Main方法中,来使用自定义的TestDbExContext类读取视图V_Person的数据,注意加上AsNoTracking方法可以提高EF Core读取数据库视图数据的效率, 因为我们不会用实体来更改数据库视图的数据,所以可以用AsNoTracking方法来取消DbContext跟踪实体V_Person:
using FFCoreView.Extension; using Microsoft.EntityFrameworkCore; using System; using System.Linq; namespace FFCoreView { class Program { static void Main(string[] args) { using(TestDbExContext dbContext=new TestDbExContext()) { var vPersons = dbContext.V_Person.AsNoTracking().ToList();//通过TestDbExContext.V_Person属性从数据库中查询视图数据,因为和数据库表不同,我们不会更新数据库视图的数据,所以调用AsNoTracking方法来告诉EF Core不用在DbContext中跟踪返回的V_Person实体,可以提高EF Core的运行效率 Console.WriteLine($"V_Person视图有{vPersons.Count.ToString()}行数据"); } Console.WriteLine("Press any key to quit..."); Console.ReadKey(); } } }
运行结果如下,我们成功读出了数据库视图V_Person的三行数据:
以上是关于EF Core 2.0中如何手动映射数据库的视图为实体的主要内容,如果未能解决你的问题,请参考以下文章
asp.net core, Ef core : 在运行时动态映射存储库和服务