1、前言
本文开始介绍一些关于Entity Framework Core
的内容。在EFCore
中,常用的为DB First
模式和Code First
模式,下面就来介绍一下如何在EFCore
中使用DB First
模式生成实体类和数据库上下文。
2、创建测试数据库
在SQL Server
中新建一个数据库Dao
,执行如下语句,创建Country
和Province
数据表。
USE [Dao]
GO
/****** Object: Table [dbo].[Country] Script Date: 2022/11/30 8:52:23 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Country](
[Id] [int] IDENTITY(1,1) NOT NULL,
[CountryName] [nvarchar](20) NULL,
CONSTRAINT [PK_Country] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
USE [Dao]
GO
/****** Object: Table [dbo].[Province] Script Date: 2022/11/30 8:53:00 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Province](
[Id] [int] IDENTITY(1,1) NOT NULL,
[ProvinceName] [nvarchar](20) NULL,
CONSTRAINT [PK_Province] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
运行结果如下图所示:
3、引入EFCore相关组件
创建一个Web API
项目,使用NuGet
引入如下四个组件,这里全部选择3.1.31
版本:
Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.Design
Microsoft.EntityFrameworkCore.Tools
4、生成实体类和数据库上下文
在EFCore
中,使用DB First
模式生成实体类和数据库上下文时需要使用Scaffold-DbContext
命令,该命令的格式如下所示:
Scaffold-DbContext [-Connection] <String> [-Provider] <String> [-OutputDir <String>] [-ContextDir <String>] [-Context <String>] [-Schemas <String[]>] [-Tables <String[]>] [-DataAnnotations] [-UseDatabaseNames] [-Force] [-Project <String>] [-StartupProject <String>][<CommonParameters>]
Scaffold-DbContext
命令中的参数说明如下表所示:
名称 | 含义 |
---|---|
-Connection | 指定数据库的连接字符串 |
-Provider | 指定要使用的提供程序。例如Microsoft.EntityFrameworkCore.SqlServer |
-OutputDir | 指定用于输出类的目录。如果省略,则使用顶级项目目录 |
-ContextDir | 指定存放DbContext的目录 |
-Context | 指定生成的DbContext类的名称 |
-Schemas | 指定要为其生成类的模式 |
-Tables | 指定要为其生成类的表 |
-DataAnnotations | 使用DataAnnotation属性在可能的情况下配置模型 |
-Force | 强制脚手架覆盖现有文件 |
-Project | 指定实体类和数据库上下文存放在的项目名称 |
-StartupProject | 指定启动项目名称 |
打开NuGet
控制台,输入如下命令:
Scaffold-DbContext -Connection "Data Source=DSF-PC;Initial Catalog=Dao;User ID=sa;Password=123456;" -Provider Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -ContextDir Context -Context DaoDbContext
运行结果如下图所示,可以发现已经创建了实体类Country
、Province
和数据库上下文类DaoDbContext
。到此为止,我们已经可以通过Scaffold-DbContext
命令生成实体类和数据库上下文了。
5、Scaffold-DbContext命令中一些参数的含义及作用
在上面的代码中,我们对Scaffold-DbContext
命令中的一些关键参数进行了设置:
-OutputDir Models
:存放实体类的文件夹名称为Models
-ContextDir Context
:存放数据库上下文的文件夹名称为Context
-Context DaoDbContext
:数据库上下文的名称为DaoDbContext
其实Scaffold-DbContext
命令中还包括一些很有用的其他参数,下面举例说明。
5.1、只对数据库中的某些表生成实体类该怎么做?
在某些情况下,我们并不希望数据库中所有的表都生成实体类,而是只将某些需要的表生成实体类即可,此时就需要对-Tables
参数进行设置,下面的代码只对Country
表生成实体类,而Province
表则不生成实体类。
Scaffold-DbContext -Connection "Data Source=DSF-PC;Initial Catalog=Dao;User ID=sa;Password=123456;" -Provider Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -ContextDir Context -Context DaoDbContext -Tables "Country"
5.2、如何生成实体类字段的数据注解?
当前的实体类字段并不包含数据注解,如下图所示:
如果需要生成数据注解,只需要添加一个-DataAnnotations
参数即可,代码如下:
Scaffold-DbContext -Connection "Data Source=DSF-PC;Initial Catalog=Dao;User ID=sa;Password=123456;" -Provider Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -ContextDir Context -Context DaoDbContext -DataAnnotations
可以发现实体类字段已经生成了对应的数据注解。
5.3、数据库被修改后如何更新实体类和数据库上下文?
当前工程中的实体类和数据库上下文如下图所示:
下面对数据库进行一些修改。首先在Dao
数据库中新增一张City
表,代码如下:
USE [Dao]
GO
/****** Object: Table [dbo].[City] Script Date: 2022/11/30 9:30:54 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[City](
[Id] [int] IDENTITY(1,1) NOT NULL,
[CityName] [nvarchar](20) NULL,
[CreateTime] [datetime] NULL,
CONSTRAINT [PK_City] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
然后在Country
表和Province
表中新增一个字段CreateTime
,代码如下:
alter table Country add [CreateTime] datetime null
alter table Province add [CreateTime] datetime null
现在对数据库的修改已经完成,下面就需要对实体类和数据库上下文进行更新了,我们只需要在Scaffold-DbContext
命令后面加上-Force
参数即可,它可以帮助我们重新生成实体类和数据库上下文并覆盖原有文件。
Scaffold-DbContext -Connection "Data Source=DSF-PC;Initial Catalog=Dao;User ID=sa;Password=123456;" -Provider Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -ContextDir Context -Context DaoDbContext -DataAnnotations -Force
可以发现覆盖后的文件已经新增了City
实体类,Country
和Province
实体类也都新增了CreateTime
字段。
5.4、分层项目中如何在其他类库中生成实体类和数据库上下文?
在实际开发过程中,很多项目都会进行分层操作,例如新建一个App.Models
类库用来存放实体类和数据库上下文,如下图所示:
如果想在App.Models
类库中生成实体类和数据库上下文也很简单,只需要按照如下步骤操作即可,首先在App.Models
中使用NuGet
引入EFCore
的相关组件,如下所示:
Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.Design
Microsoft.EntityFrameworkCore.Tools
然后生成一下解决方案:
最后在Scaffold-DbContext
命令中设置-Project
和-StartupProject
参数,代码如下:
Scaffold-DbContext -Connection "Data Source=DSF-PC;Initial Catalog=Dao;User ID=sa;Password=123456;" -Provider Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -ContextDir Context -Context DaoDbContext -DataAnnotations -Force -Project App.Models -StartupProject App.Models
可以发现在App.Models
项目中已经生成了实体类和数据库上下文。
6、注入数据库上下文
现在实体类和数据库上下文都有了,接下来只需要在Controller
中将其注入即可。首先在appsettings.json
文件中配置数据库连接字符串,代码如下:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"ConnectionString": "Data Source=DSF-PC;Initial Catalog=Dao;User ID=sa;Password=123456;"
}
}
然后在Startup.cs
文件中添加数据库上下文,代码如下所示:
using App.Context;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace App
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// 添加控制器
services.AddControllers();
// 添加数据库上下文
services.AddDbContext<DaoDbContext>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("ConnectionString"));
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
最后新建一个控制器CountryController.cs
,将DaoDbContext
注入即可,代码如下:
using App.Context;
using App.Models;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Linq;
namespace App.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class CountryController : ControllerBase
{
protected readonly DaoDbContext _dbContext;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="dbContext"></param>
public CountryController(DaoDbContext dbContext)
{
_dbContext = dbContext;
}
/// <summary>
/// 添加实体集合
/// </summary>
/// <returns></returns>
[HttpGet]
public ActionResult<string> Add()
{
List<Country> list = new List<Country>
{
new Country { CountryName = "中国" },
new Country { CountryName = "美国" },
new Country { CountryName = "俄罗斯" }
};
_dbContext.Set<Country>().AddRange(list);
_dbContext.SaveChanges();
return "添加实体成功";
}
/// <summary>
/// 获取实体集合
/// </summary>
/// <returns></returns>
[HttpGet]
public ActionResult<List<Country>> Get()
{
return _dbContext.Set<Country>().ToList();
}
}
}
执行Add
方法后,运行结果如下图所示:
执行Get
方法后,运行结果如下图所示:
7、结语
本文主要介绍了一些关于EFCore
中DB First
开发模式的内容,对于Scaffold-DbContext
命令中其他的参数含义及作用,有兴趣的同志也可以自行深入研究。如果你参与的项目之前就已经存在数据库,那么选用DB First
模式可能会更加方便友好。