1 表及其字段的约束规则定义
1.1 Data.Mapping.Users.RoleBuilder
//Nuget
//Nuget--Microsoft.EntityFrameworkCore.SqlServer
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
//项目
using Core.Domain.Users;
namespace Data.Mapping.Users
{
/// <summary>
/// 【角色生成器--类】
/// <remarks>
/// 摘要:
/// 该类通过对“EntityFrameworkCore”中间件“IEntityTypeConfiguration<>”泛型接口的“Configure”方法的定义,以实现把角色实体类及其属性成员相关约束规则及其级联关系定义,映射到角色表及其的相应字段上。
/// </remarks>
/// </summary>
public class RoleBuilder : IEntityTypeConfiguration<Role>
{
#region 方法--IEntityTypeConfiguration<>
///<param name="builder">实体类型生成器实例,用于把当前程序中指定实体和属性所定义的约束规则,映射到数据库指定表及其字段上。</param>
/// <summary>
/// 【配置】
/// <remarks>
/// 摘要:
/// 该方法通过对“EntityFrameworkCore”中间件“IEntityTypeConfiguration<>”泛型接口的“Configure”方法的定义,以实现把角色实体类及其属性成员相关约束规则及其级联关系定义,映射到角色表及其的相应字段上。
/// </remarks>
/// </summary>
public void Configure(EntityTypeBuilder<Role> builder)
{
//由于“EntityTypeBuilder<Role>”的参数已经泛型实例化,因此builder后不能再定义为:“builder.Entity<Role>().HasKey(role => role.Id);”。
//角色表及其字段约束规则,映射定义。
builder.HasKey(role => role.Id);
builder.Property(role => role.Name).IsRequired().HasMaxLength(255);
}
#endregion
}
}
1.2 Data.Mapping.Users.UserBuilder
//Nuget
//Nuget--Microsoft.EntityFrameworkCore.SqlServer
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
//项目
using Core.Domain.Users;
namespace Data.Mapping.Users
{
/// <summary>
/// 【用户生成器--类】
/// <remarks>
/// 摘要:
/// 该类通过对“EntityFrameworkCore”中间件“IEntityTypeConfiguration<>”泛型接口的“Configure”方法的定义,以实现把用户实体类及其属性成员相关约束规则及其级联关系定义,映射到用户表及其的相应字段上。
/// </remarks>
/// </summary>
public class UserBuilder : IEntityTypeConfiguration<User>
{
#region 方法--IEntityTypeConfiguration<>
///<param name="builder">实体类型生成器实例,用于把当前程序中指定实体和属性所定义的约束规则,映射到数据库指定表及其字段上。</param>
/// <summary>
/// 【配置】
/// <remarks>
/// 摘要:
/// 该方法通过对“EntityFrameworkCore”中间件“IEntityTypeConfiguration<>”泛型接口的“Configure”方法的定义,以实现把用户实体类及其属性成员相关约束规则及其级联关系定义,映射到用户表及其的相应字段上。
/// </remarks>
/// </summary>
public void Configure(EntityTypeBuilder<User> builder)
{
//由于“EntityTypeBuilder<User>”的参数已经泛型实例化,因此builder后不能再定义为:“builder.Entity<User>().HasKey(user => user.Id);”。
//用户表及其字段约束规则,映射定义。
builder.HasKey(user => user.Id);
builder.Property(user => user.Name).IsRequired().HasMaxLength(255);
builder.Property(user => user.Email).IsRequired().HasMaxLength(255);
builder.Property(user => user.Password).IsRequired().HasMaxLength(255);
builder.Property(user => user.Phone).HasMaxLength(50);
builder.Property(user => user.RememberToken).HasMaxLength(500);
builder.Property(user => user.Avatar).HasMaxLength(255);
builder.Property(user => user.CreatedDateTime).IsRequired();
builder.Property(user => user.UpdatedDateTime).IsRequired();
builder.Ignore(user => user.RoleCollection);
}
#endregion
}
}
1.3 Data.Mapping.Users.UserRoleBuilder
//Nuget
//Nuget--Microsoft.EntityFrameworkCore.SqlServer
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
//项目
using Core.Domain.Users;
namespace Data.Mapping.Users
{
/// <summary>
/// 【用户角色映射生成器--类】
/// <remarks>
/// 摘要:
/// 该类通过对“EntityFrameworkCore”中间件“IEntityTypeConfiguration<>”泛型接口的“Configure”方法的定义,以实现把用户角色映射实体类及其属性成员相关约束规则及其级联关系定义,映射到用户角色映射表及其的相应字段上。
/// </remarks>
/// </summary>
public class UserRoleBuilder : IEntityTypeConfiguration<UserRole>
{
#region 方法--IEntityTypeConfiguration<>
///<param name="builder">实体类型生成器实例,用于把当前程序中指定实体和属性所定义的约束规则,映射到数据库指定表及其字段上。</param>
/// <summary>
/// 【配置】
/// <remarks>
/// 摘要:
/// 该方法通过对“EntityFrameworkCore”中间件“IEntityTypeConfiguration<>”泛型接口的“Configure”方法的定义,以实现把用户角色映射实体类及其属性成员相关约束规则及其级联关系定义,映射到用户角色映射表及其的相应字段上。
/// </remarks>
/// </summary>
public void Configure(EntityTypeBuilder<UserRole> builder)
{
//由于“EntityTypeBuilder<UserRole>”的参数已经泛型实例化,因此builder后不能再定义为:“builder.Entity<UserRole>().HasKey(userRole => new { userRole.UserId, userRole.RoleId });”。
//用户角色映射表及其字段约束规则,映射定义。
builder.HasKey(userRole => new { userRole.UserId, userRole.RoleId });
builder.HasOne(userRole => userRole.UserSingle)
.WithMany(user => user.UserRoleCollection)
.HasForeignKey(userRole => userRole.UserId)
.IsRequired();
builder.HasOne(userRole => userRole.RoleSingle)
.WithMany()
.HasForeignKey(userRole => userRole.RoleId)
.IsRequired();
builder.Ignore(userRole => userRole.Id);
}
#endregion
}
}
1.4 Data.Mapping.Security.PermissionBuilder
//Nuget
//Nuget--Microsoft.EntityFrameworkCore.SqlServer
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
//项目
using Core.Domain.Security;
namespace Data.Mapping.Security
{
/// <summary>
/// 【权限生成器--类】
/// <remarks>
/// 摘要:
/// 该类通过对“EntityFrameworkCore”中间件“IEntityTypeConfiguration<>”泛型接口的“Configure”方法的定义,以实现把权限实体类及其属性成员相关约束规则及其级联关系定义,映射到权限表及其的相应字段上。
/// </remarks>
/// </summary>
public class PermissionBuilder : IEntityTypeConfiguration<Permission>
{
#region 方法--IEntityTypeConfiguration<>
///<param name="builder">实体类型生成器实例,用于把当前程序中指定实体和属性所定义的约束规则,映射到数据库指定表及其字段上。</param>
/// <summary>
/// 【配置】
/// <remarks>
/// 摘要:
/// 该方法通过对“EntityFrameworkCore”中间件“IEntityTypeConfiguration<>”泛型接口的“Configure”方法的定义,以实现把权限实体类及其属性成员相关约束规则及其级联关系定义,映射到权限表及其的相应字段上。
/// </remarks>
/// </summary>
public void Configure(EntityTypeBuilder<Permission> builder)
{
//由于“EntityTypeBuilder<Permission>”的参数已经泛型实例化,因此builder后不能再定义为:“builder.Entity<Permission>().HasKey(permission => permission.Id);”。
//权限表及其字段约束规则,映射定义。
builder.HasKey(permission => permission.Id);
builder.Property(permission => permission.Name).IsRequired().HasMaxLength(255);
builder.Property(permission => permission.Category).IsRequired().HasMaxLength(500);
}
#endregion
}
}
1.5 Data.Mapping.Security.PermissionRoleBuilder
//Nuget
//Nuget--Microsoft.EntityFrameworkCore.SqlServer
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
//项目
using Core.Domain.Security;
namespace Data.Mapping.Security
{
/// <summary>
/// 【权限角色映射生成器--类】
/// <remarks>
/// 摘要:
/// 该类通过对“EntityFrameworkCore”中间件“IEntityTypeConfiguration<>”泛型接口的“Configure”方法的定义,以实现把权限角色映射实体类及其属性成员相关约束规则及其级联关系定义,映射到权限角色映射表及其的相应字段上。
/// </remarks>
/// </summary>
public class PermissionRoleBuilder : IEntityTypeConfiguration<PermissionRole>
{
#region 方法--IEntityTypeConfiguration<>
///<param name="builder">实体类型生成器实例,用于把当前程序中指定实体和属性所定义的约束规则,映射到数据库指定表及其字段上。</param>
/// <summary>
/// 【配置】
/// <remarks>
/// 摘要:
/// 该方法通过对“EntityFrameworkCore”中间件“IEntityTypeConfiguration<>”泛型接口的“Configure”方法的定义,以实现把权限角色映射实体类及其属性成员相关约束规则及其级联关系定义,映射到权限角色映射表及其的相应字段上。
/// </remarks>
/// </summary>
public void Configure(EntityTypeBuilder<PermissionRole> builder)
{
//由于“EntityTypeBuilder<Role>”的参数已经泛型实例化,因此builder后不能再定义为:“builder.Entity<PermissionRole>().HasKey(permissionRole => new { permissionRole.PermissionId, permissionRole.RoleId });”。
//权限角色映射表及其字段约束规则,映射定义。
builder.HasKey(permissionRole => new { permissionRole.PermissionId, permissionRole.RoleId });
builder.HasOne(permissionRole => permissionRole.PermissionSingle)
.WithMany(permission => permission.PermissionRoleCollection)
.HasForeignKey(permissionRole => permissionRole.PermissionId)
.IsRequired();
builder.HasOne(permissionRole => permissionRole.RoleSingle)
.WithMany(role => role.PermissionRoleCollection)
.HasForeignKey(permissionRole => permissionRole.RoleId)
.IsRequired();
builder.Ignore(permissionRole => permissionRole.Id);
}
#endregion
}
}
2 重构Data.EFCoreContext
//Nuget
//Nuget--Microsoft.EntityFrameworkCore.SqlServer
using Microsoft.EntityFrameworkCore;
//项目
using Core.Domain;
using System.Reflection;
namespace Data
{
/// <summary>
/// 【EFCore上下文】
/// <remarks>
/// 摘要:
/// 基类构造方法通过该类构造方法中的参数实例,实例化了“Microsoft.EntityFrameworkCore.SqlServer”中间件,
/// 以实现“Microsoft.EntityFrameworkCore.SqlServer”中间件与指定数据库(SQL Server)数据库软件中的指定数据库的连接,
/// 最终达到实体与相应表之间通过“Microsoft.EntityFrameworkCore.SqlServer”中间件进行CURD的交互操作的目的(功能)。
/// </remarks>
/// </summary>
public class EFCoreContext : DbContext
{
#region 拷贝构造方法
///<param name="options">配置参数实例,通过配置参数实例,调用基类的拷贝构造方法以实现“Microsoft.EntityFrameworkCore.SqlServer”中间件与(SQL Server)数据库软件中指定数据库的连接。</param>
/// <summary>
/// 【拷贝构造方法】
/// <remarks>
/// 摘要:
/// 基类构造方法通过该类构造方法中的参数实例,实例化了“Microsoft.EntityFrameworkCore.SqlServer”中间件,
/// 以实现“Microsoft.EntityFrameworkCore.SqlServer”中间件与指定数据库(SQL Server)数据库软件中的指定数据库的连接,
/// 最终达到实体与相应表之间通过“Microsoft.EntityFrameworkCore.SqlServer”中间件进行CURD的交互操作的目的(功能)。
/// </remarks>
/// </summary>
public EFCoreContext(DbContextOptions<EFCoreContext> options) : base(options)
{
//如果(SQL Server)数据库软件中没有指定的数据库, 当通过Code First模式时,在第1次生成数据库时,则通过下1行语句结合数据库连接字符串,在(SQL Server)数据库软件中生成指定的数据库数据库、表和字段。
Database.EnsureCreated();
/*
如果(SQL Server)数据库软件中没有指定的数据库, 当通过Code First模式时,在第1次生成数据库时,则也通过下行执行迁移和更新命令行的结合数据库连接字符串,在(SQL Server)数据库软件中生成指定的数据库数据库、表和字段。
Add-Migration Initialize(Initialize:自动生成的迁移类名,这里特指:20220803125612_Initialize.cs):
Update-Database Initialize(通过自动生成的迁移类中的定义,自动在指定的数据库软件中生成指定的数据库、表、字段和约束规则)
*/
}
#endregion
#region 虚方法
///<typeparam name="TEntity">泛型类型实例(这里限定了于“BaseEntity”抽象类的实体类的类型实例)。</typeparam>
/// <summary>
/// 【获取数据库设置】
/// <remarks>
/// 摘要:
/// 该方法通过泛型方式获取1个指定实体的数据库设置实例(DbSet),以实现指定实体与指定表之间的CURD的交互操作,并把这些数据存储到数据库设置实例中(内存)。
/// </remarks>
/// <returns>
/// 返回:
/// 1个指定实体的数据库设置实例(DbSet),以实现指定实体与指定表之间的CURD的交互操作,并把这些数据存储到数据库设置实例中(内存)。
/// </returns>
/// </summary>
public virtual DbSet<TEntity> GetDbSet<TEntity>() where TEntity : BaseEntity
{
return base.Set<TEntity>();
}
#endregion
#region 方法--私有/保护--覆写
///<param name="builder">模型生成器实例,用于把当前程序中实体和属性所定义的约束规则,映射到数据库指定表及其字段上。</param>
/// <summary>
/// 【模型生成执行...】
/// <remarks>
/// 摘要:
/// 该方法把当前程序中实体和属性所定义的约束规则,映射到数据库指定表及其字段上。
/// </remarks>
/// </summary>
protected override void OnModelCreating(ModelBuilder builder)
{
//EntityFrameworkCore <= 2.1或EntityFrameworkCore <= 2.1~EntityFrameworkCore = 7.0.1(至今)。
//通过反射方式把“Data”项目中所有继承“IEntityTypeConfiguration<>”泛型接口的表及其字段约束规则定义类进行实现化操作,
//优点:有过滤操作,只获取继承“IEntityTypeConfiguration<>”泛型接口的具体实现类。
//缺点:没有下述方式简单。
//List<Type> _typeBuilderList = Assembly.GetExecutingAssembly().GetTypes()
// .Where(t => t.GetInterfaces().Any(gi => gi.IsGenericType && gi.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>)))
// .ToList();
//foreach (var type in _typeBuilderList)
//{
// //依次对继承“IEntityTypeConfiguration<>”泛型接口的表及其字段约束规则定义类进行实现化操作。
// dynamic _configurationInstance = Activator.CreateInstance(type);
// builder.ApplyConfiguration(_configurationInstance);
//}
//EntityFrameworkCore> = 2.2或EntityFrameworkCore> = 2.2~EF Core = 7.0.1(至今)。
//通过反射方式把“Data”项目中所有继承“IEntityTypeConfiguration<>”泛型接口的表及其字段约束规则定义类进行实现化操作,
//优点:该方式简单,由于表及其字段约束规则在整个软件运行的生命周期中,只有1次,所以整个程序的开销不大。
//缺点:没有过滤操作,性能上不如上述方式。黑盒化严重。
builder.ApplyConfigurationsFromAssembly(this.GetType().Assembly);
base.OnModelCreating(builder);
}
#endregion
}
}
3重构WebApi.Controllers.WeatherForecastController.Get方法
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<Role> Get()
{
return _context.GetDbSet<Role>().ToList();
}
4 EntityFrameworkCore与SqlSugar
由于SqlSugar是国内开发者所开发的CURD开源中间件,比EntityFrameworkCore中间件的资源多的多,其内置功能实现也比EntityFrameworkCore中间件多,调用习惯也更加符合国内的开发者,学习曲线也低的多,但是到目前为止SqlSugar(V5.1.3.41)中间件还不支持抽离表及其字段的约束规则定义, 约束规则依然需要通过特性与实体属性成员结合才能实实现表及其字段的约束规则定义,这样实体与表的约束定义形成了紧密的耦合关系,因此在SqlSugar中间件解决这个问题前,本人通过权衡最终选择了EntityFrameworkCore中间件实现实体与表之间的CRUD操作。
按F5执行程序,执行“GetWeatherForecast”Api,即可自动生成数据库及其表。
对以上功能更为具体实现和注释见:221219_002ShopDemo(抽离表及其字段的约束规则定义)。