章将通过对示例“22-09-29-03_SqlSugarAcquaintance(初识SqlSugarCore之ConfigureOptions注入实现)”的重构,在Code-Frist模式下,把多个实体及其特性通过“SqlSugarCore”中间件,一次性的在指定的数据库软件的指定数据库中自动生成所有的表、字段及其相应的约束规则。
1 定义多个实体及其相应的实体特性
1.1 重构Specialty(专业)实体及其相应的实体特性的定义
///
/// 【专业--类】
///
/// 摘要:
/// 通过该实体类及其属性成员,用于实现当前程序【Data】.【领域】.【学生集】.【专业】实体与“[SqlSugarAcquaintance].[Specialty]”表之间的CURD的交互操作,并把这些数据存储到数据库设置实例中(内存)。
///
///
public class Specialty
{
///
/// 【编号】
///
///
/// 摘要:
/// 获取/设置专业实体1个指定实例的整型编号值。
/// [SugarColumn(IsIdentity = true, IsPrimaryKey = true)]标记:
/// 该标记将该属性成员所映射[Specialty].[Id]字段约束定义主键。
///
[SugarColumn(IsIdentity = true, IsPrimaryKey = true)]
public int Id { get; set; }
///
/// 【名称】
///
///
/// 摘要:
/// 获取/设置1个指定专业的名称。
///[SugarColumn(ColumnDataType = "nvarchar", Length =255)]标记:
/// 该标记将该属性成员所映射[Specialty].[Name]字段的长度约束定义为:“255”,字段长度约束的默认类型为:“varchar,当前设定类型为;“nvarchar”
/// 同时标记的约束定义权限高于上下文约束定义的权限,即指定表中指定字段长度的约束类型和长度,最终将由该标记约束定义所决定。
///
[SugarColumn(ColumnDataType = "nvarchar", Length = 255)]
public string Name { get; set; }
///
/// 【学生集】
///
///
/// 摘要:
/// 获取/设置学生表中的所有学生实例。
/// [SugarColumn(IsIgnore = true)]标记:
/// 该属性成员将不被映射为对应表中的字段。
/// [Navigate(NavigateType.OneToMany, nameof(Student.SpecialtyId))]
/// 该标记主要用于把[SqlSugarAcquaintance].[Student]表中的所有数据存储在该属性成员的实例中,
/// 注意:
/// “SqlSugarCore”中间件不支持外键/副键约束映射定义,即在Code-Frist模式下,实体所映射生成的表中不存在被约束定义为外键/副键的字段,
/// 那么与外键/副键相关的级联操作也将不复存在,所以该属性成员只有数据存储功能而不像“EFCore”那样还兼具着外键/副键约束映射定义功能。
///
[SugarColumn(IsIgnore = true)]
[Navigate(NavigateType.OneToMany, nameof(Student.SpecialtyId))]
public virtual ICollection
}
1.2 Course(课程)实体及其相应的实体特性的定义
///
/// 【课程--类】
///
/// 摘要:
/// 通过该实体类及其属性成员,用于实现当前程序【Data】.【领域】.【学生集】.【课程】实体与“[SqlSugarAcquaintance].[Course]”表之间的CURD的交互操作,并把这些数据存储到数据库设置实例中(内存)。
///
///
public class Course
{
///
/// 【编号】
///
///
/// 摘要:
/// 获取/设置课程实体1个指定实例的整型编号值。
/// [SugarColumn(IsIdentity = true, IsPrimaryKey = true)]标记:
/// 该标记将该属性成员所映射[Course].[Id]字段约束定义主键。
///
[SugarColumn(IsIdentity = true, IsPrimaryKey = true)]
public int Id { get; set; }
///
/// 【名称】
///
///
/// 摘要:
/// 获取/设置1个指定课程的名称。
/// [SugarColumn(ColumnDataType = "nvarchar", Length =255)]标记:
/// 该标记将该属性成员所映射[Course].[Name]字段的长度约束定义为:“255”,字段长度约束的默认类型为:“varchar,当前设定类型为;“nvarchar”
/// 同时标记的约束定义权限高于上下文约束定义的权限,即指定表中指定字段长度的约束类型和长度,最终将由该标记约束定义所决定。
///
[SugarColumn(ColumnDataType = "nvarchar", Length = 255)]
public string Name { get; set; }
///
/// 【成绩集】
///
///
/// 摘要:
/// 获取/设置成绩表中的所有成绩实例。
/// [SugarColumn(IsIgnore = true)]标记:
/// 该属性成员将不被映射为对应表中的字段。
/// [Navigate(NavigateType.OneToMany, nameof(Score.CourseId))]
/// 该标记主要用于把[SqlSugarAcquaintance].[Score]表中的所有数据存储在该属性成员的实例中,
/// 注意:
/// “SqlSugarCore”中间件不支持外键/副键约束映射定义,即在Code-Frist模式下,实体所映射生成的表中不存在被约束定义为外键/副键的字段,
/// 那么与外键/副键相关的级联操作也将不复存在,所以该属性成员只有数据存储功能而不像“EFCore”那样还兼具着外键/副键约束映射定义功能。
///
[SugarColumn(IsIgnore = true)]
[Navigate(NavigateType.OneToMany, nameof(Score.CourseId))]
public virtual ICollection
}
1.3 Grade(年级)实体及其相应的实体特性的定义
///
/// 【年级--类】
///
/// 摘要:
/// 通过该实体类及其属性成员,用于实现当前程序【Data】.【领域】.【学生集】.【年级】实体与“[SqlSugarAcquaintance].[Grade]”表之间的CURD的交互操作,并把这些数据存储到数据库设置实例中(内存)。
///
///
public class Grade
{
///
/// 【编号】
///
///
/// 摘要:
/// 获取/设置年级实体1个指定实例的整型编号值。
/// [SugarColumn(IsIdentity = true, IsPrimaryKey = true)]标记:
/// 该标记将该属性成员所映射[Grade].[Id]字段约束定义主键。
///
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public int Id { get; set; }
///
/// 【名称】
///
///
/// 摘要:
/// 获取/设置1个指定年级的名称。
/// [SugarColumn(ColumnDataType = "nvarchar", Length =255)]标记:
/// 该标记将该属性成员所映射[Grade].[Name]字段的长度约束定义为:“255”,字段长度约束的默认类型为:“varchar,当前设定类型为;“nvarchar”
/// 同时标记的约束定义权限高于上下文约束定义的权限,即指定表中指定字段长度的约束类型和长度,最终将由该标记约束定义所决定。
///
[SugarColumn(ColumnDataType = "nvarchar", Length = 255)]
public string Name { get; set; }
///
/// 【班级集】
///
///
/// 摘要:
/// 获取/设置学生表中的所有学生实例。
/// [SugarColumn(IsIgnore = true)]标记:
/// 该属性成员将不被映射为对应表中的字段。
/// [Navigate(NavigateType.OneToMany, nameof(Category.GradeId))]
/// 该标记主要用于把[SqlSugarAcquaintance].[Category]表中的所有数据存储在该属性成员的实例中,
/// 注意:
/// “SqlSugarCore”中间件不支持外键/副键约束映射定义,即在Code-Frist模式下,实体所映射生成的表中不存在被约束定义为外键/副键的字段,
/// 那么与外键/副键相关的级联操作也将不复存在,所以该属性成员只有数据存储功能而不像“EFCore”那样还兼具着外键/副键约束映射定义功能。
///
[SugarColumn(IsIgnore = true)]
[Navigate(NavigateType.OneToMany, nameof(Category.GradeId))]//1:n
public virtual ICollection
}
1.4 Category(班级)实体及其相应的实体特性的定义
///
/// 【班级--类】
///
///
/// 摘要:
/// 通过该实体类及其属性成员,用于实现当前程序【Data】.【领域】.【学生集】.【班级】实体与“[SqlSugarAcquaintance].[Category]”表之间的CURD的交互操作,并把这些数据存储到数据库设置实例中(内存)。
///
public class Category
{
///
/// 【编号】
///
///
/// 摘要:
/// 获取/设置班级实体1个指定实例的整型编号值。
/// [SugarColumn(IsIdentity = true, IsPrimaryKey = true)]标记:
/// 该标记将该属性成员所映射[Category].[Id]字段约束定义主键。
///
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public int Id { get; set; }
///
/// 【年级编号】
///
///
/// 摘要:
/// 获取/设置年级实体1个指定实例的整型编号值。
/// 注意:
/// “SqlSugarCore”中间件不支持外键/副键约束映射定义,即在Code-Frist模式下,该属性成员不能像“EFCore”那样被约束定义为:外键/副键
///
public int GradeId { get; set; }
///
/// 【名称】
///
///
/// 摘要:
/// 获取/设置1个指定班级的名称。
/// [SugarColumn(ColumnDataType = "nvarchar", Length =255)]标记:
/// 该标记将该属性成员所映射[Category].[Name]字段的长度约束定义为:“255”,字段长度约束的默认类型为:“varchar,当前设定类型为;“nvarchar”
/// 同时标记的约束定义权限高于上下文约束定义的权限,即指定表中指定字段长度的约束类型和长度,最终将由该标记约束定义所决定。
///
[SugarColumn(ColumnDataType = "nvarchar", Length = 255)]
public string Name { get; set; }
///
/// 【单个年级】
///
///
/// 摘要:
/// 获取/设置年级实体的1个指定实例。
/// [[Navigate(NavigateType.OneToOne, nameof(GradeId))]
/// 该标记在当前程序使用级联查询操作时,直接获取年级实体的1个指定实例,如果该属性没有被该标记所标记则在使用级联查询操作时会出现异常。
///
[SugarColumn(IsIgnore = true)]
[Navigate(NavigateType.OneToOne, nameof(GradeId))]//1:1
public virtual Grade GradeSingleton { get; set; }
///
/// 【班级集】
///
///
/// 摘要:
/// 获取/设置班级表中的所有班级实例。
/// [SugarColumn(IsIgnore = true)]标记:
/// 该属性成员将不被映射为对应表中的字段。
/// Navigate(NavigateType.OneToMany, nameof(Student.CategoryId))]标记:
/// 该标记主要用于把[SqlSugarAcquaintance].[Student]表中的所有数据存储在该属性成员的实例中,
/// 注意:
/// “SqlSugarCore”中间件不支持外键/副键约束映射定义,即在Code-Frist模式下,实体所映射生成的表中不存在被约束定义为外键/副键的字段,
/// 那么与外键/副键相关的级联操作也将不复存在,所以该属性成员只有数据存储功能而不像“EFCore”那样还兼具着外键/副键约束映射定义功能。
///
[SugarColumn(IsIgnore = true)]
[Navigate(NavigateType.OneToMany, nameof(Student.CategoryId))]
public virtual ICollection
}
1.5 Student(学生)实体及其相应的实体特性的定义
///
/// 【学生--类】
///
///
/// 摘要:
/// 通过该实体类及其属性成员,用于实现当前程序【Data】.【领域】.【学生集】.【学生】实体与“[SqlSugarAcquaintance].[Student]”表之间的CURD的交互操作,并把这些数据存储到数据库设置实例中(内存)。
///
public class Student
{
///
/// 【编号】
///
///
/// 摘要:
/// 获取/设置学生实体1个指定实例的整型编号值。
/// [SugarColumn(IsIdentity = true, IsPrimaryKey = true)]标记:
/// 该标记将该属性成员所映射[Specialty].[Id]字段约束定义主键。
///
[SugarColumn(IsIdentity = true, IsPrimaryKey = true)]
public int Id { get; set; }
///
/// 【专业编号】
///
///
/// 摘要:
/// 获取/设置专业实体1个指定实例的整型编号值。
/// 注意:
/// “SqlSugarCore”中间件不支持外键/副键约束映射定义,即在Code-Frist模式下,该属性成员不能像“EFCore”那样被约束定义为:外键/副键
///
public int SpecialtyId { get; set; }
///
/// 【班级编号】
///
///
/// 摘要:
/// 获取/设置班级实体1个指定实例的整型编号值。
/// 注意:
/// “SqlSugarCore”中间件不支持外键/副键约束映射定义,即在Code-Frist模式下,该属性成员不能像“EFCore”那样被约束定义为:外键/副键
///
public int CategoryId { get; set; }
///
/// 【学号】
///
///
/// 摘要:
/// 获取/设置学生实体1个指定实例的学号。
/// [SugarColumn(ColumnDataType = "nvarchar", Length =int.MaxValue)]标记:
/// 该标记将该属性成员所映射[Course].[Name]字段的长度约束定义为:“20”,字段长度约束的默认类型为:“varchar,当前设定类型为;“nvarchar”
/// 同时标记的约束定义权限高于上下文约束定义的权限,即指定表中指定字段长度的约束类型和长度,最终将由该标记约束定义所决定。
///
[SugarColumn(ColumnDataType = "nvarchar", Length = 20)]
public string Code { get; set; }
///
/// 【姓名】
///
///
/// 摘要:
/// 获取/设置1个指定学生的姓名。
/// [SugarColumn(ColumnDataType = "nvarchar", Length =20)]标记:
/// 该标记将该属性成员所映射[Course].[Name]字段的长度约束定义为:“20”,字段长度约束的默认类型为:“varchar,当前设定类型为;“nvarchar”
/// 同时标记的约束定义权限高于上下文约束定义的权限,即指定表中指定字段长度的约束类型和长度,最终将由该标记约束定义所决定。
///
[SugarColumn(ColumnDataType = "nvarchar", Length = 20)]
public string Name { get; set; }
///
/// 【单个专业】
///
///
/// 摘要:
/// 获取/设置专业实体的1个指定实例。
/// [Navigate(NavigateType.OneToOne, nameof(SpecialtyId))]标记:
/// 该标记在当前程序使用级联查询操作时,直接获取专业实体的1个指定实例,如果该属性没有被该标记所标记则在使用级联查询操作时会出现异常。
///
[SugarColumn(IsIgnore = true)]
[Navigate(NavigateType.OneToOne, nameof(SpecialtyId))]//1:1
public virtual Specialty SpecialtySingleton { get; set; }
///
/// 【单个班级】
///
///
/// 摘要:
/// 获取/设置班级实体的1个指定实例。
/// [Navigate(NavigateType.OneToOne, nameof(CategoryId))]标记:
/// 该标记在当前程序使用级联查询操作时,直接获取班级实体的1个指定实例,如果该属性没有被该标记所标记则在使用级联查询操作时会出现异常。
///
[SugarColumn(IsIgnore = true)]
[Navigate(NavigateType.OneToOne, nameof(CategoryId))]//1:1
public virtual Category CategorySingleton { get; set; }
///
/// 【成绩集】
///
///
/// 摘要:
/// 获取/设置成绩表中的所有成绩实例。
/// [SugarColumn(IsIgnore = true)]标记:
/// 该属性成员将不被映射为对应表中的字段。
/// [Navigate(NavigateType.OneToMany, nameof(Score.StudentId))]
/// 该标记主要用于把[SqlSugarAcquaintance].[Score]表中的所有数据存储在该属性成员的实例中,
/// 注意:
/// “SqlSugarCore”中间件不支持外键/副键约束映射定义,即在Code-Frist模式下,实体所映射生成的表中不存在被约束定义为外键/副键的字段,
/// 那么与外键/副键相关的级联操作也将不复存在,所以该属性成员只有数据存储功能而不像“EFCore”那样还兼具着外键/副键约束映射定义功能。
///
[SugarColumn(IsIgnore = true)]
[Navigate(NavigateType.OneToMany, nameof(Score.StudentId))]
public virtual ICollection
}
1.6 Score(成绩)实体及其相应的实体特性的定义
///
/// 【成绩--类】
///
/// 摘要:
/// 通过该实体类及其属性成员,用于实现当前程序【Data】.【领域】.【学生集】.【成绩】实体与“[SqlSugarAcquaintance].[Score]”表之间的CURD的交互操作,并把这些数据存储到数据库设置实例中(内存)。
///
///
public class Score
{
///
/// 【编号】
///
///
/// 摘要:
/// 获取/设置成绩实体1个指定实例的整型编号值。
/// [SugarColumn(IsIdentity = true, IsPrimaryKey = true)]标记:
/// 该标记将该属性成员所映射[Score].[Id]字段约束定义主键。
///
[SugarColumn(IsIdentity = true, IsPrimaryKey = true)]
public int Id { get; set; }
///
/// 【学生编号】
///
///
/// 摘要:
/// 获取/设置班级实体1个指定实例的整型编号值。
/// 注意:
/// “SqlSugarCore”中间件不支持外键/副键约束映射定义,即在Code-Frist模式下,该属性成员不能像“EFCore”那样被约束定义为:外键/副键
///
public int StudentId { get; set; }
///
/// 【课程编号】
///
///
/// 摘要:
/// 获取/设置课程实体1个指定实例的整型编号值。
/// 注意:
/// “SqlSugarCore”中间件不支持外键/副键约束映射定义,即在Code-Frist模式下,该属性成员不能像“EFCore”那样被约束定义为:外键/副键
///
public int CourseId { get; set; }
///
/// 【名称】
///
///
/// 摘要:
/// 获取/设置一次考试的名称。
///[SugarColumn(ColumnDataType = "nvarchar", Length =255)]标记:
/// 该标记将该属性成员所映射[Course].[Name]字段的长度约束定义为:“255”,字段长度约束的默认类型为:“varchar,当前设定类型为;“nvarchar”
/// 同时标记的约束定义权限高于上下文约束定义的权限,即指定表中指定字段长度的约束类型和长度,最终将由该标记约束定义所决定。
///
[SugarColumn(ColumnDataType = "nvarchar", Length = 255)]
public string Name { get; set; }
///
/// 【成绩】
///
///
/// 摘要:
/// 获取/设置1个指定成绩实例中的成绩整型值。
///
[SugarColumn(IsNullable = true)]
public int? Socre { get; set; }
///
/// 【备注】
///
///
/// 摘要:
/// 获取/设置1个指定成绩实例中的备注信息。
/// [SugarColumn(IsNullable = true, ColumnDataType = "nvarchar", Length = int.MaxValue)]标记:
/// 该标记将该属性成员所映射[Course].[Comment]字段的长度约束定义为:“int.MaxValue”,字段长度约束的默认类型为:“varchar,当前设定类型为;“nvarchar”
/// 同时标记的约束定义权限高于上下文约束定义的权限,即指定表中指定字段长度的约束类型和长度,最终将由该标记约束定义所决定。
///
[SugarColumn(IsNullable = true, ColumnDataType = "nvarchar", Length = int.MaxValue)]
public string Comment { get; set; }
///
/// 【单个学生】
///
///
/// 摘要:
/// 获取/设置专业实体的1个指定实例。
/// [Navigate(NavigateType.OneToOne, nameof(StudentId))]
/// 该标记在当前程序使用级联查询操作时,直接获取学生实体的1个指定实例,如果该属性没有被该标记所标记则在使用级联查询操作时会出现异常。
///
[SugarColumn(IsIgnore = true)]
[Navigate(NavigateType.OneToOne, nameof(StudentId))]//1:1
public virtual Student StudentSingleton { get; set; }
///
/// 【单个课程】
///
///
/// 摘要:
/// 获取/设置年级实体的1个指定实例。
/// [Navigate(NavigateType.OneToOne, nameof(CourseId))]
/// 该标记在当前程序使用级联查询操作时,直接获取课程实体的1个指定实例,如果该属性没有被该标记所标记则在使用级联查询操作时会出现异常。
///
[SugarColumn(IsIgnore = true)]
[Navigate(NavigateType.OneToOne, nameof(CourseId))]//1:1
public virtual Course CourseSingleton { get; set; }
}
2、根据实体定义一次性的生成所有的表。
2.1 重构CreateTable方法为:
#region 方法--私有/保护
/// name="backup">指示在指定的数据库软件中自动生成指定的数据库及其表后,指定数据库软件是否支持对该数据库执行自动备份操作,默认值:false,即不执行自动备份操作。
/// name="stringDefaultLength">
/// 数据库中所有字符串类型字段的长度约束值,默认值:50,设置所有字串类型的字段的默认长度为:“varchar(50)”,
/// SqlSugarCore字符串类型默认约束映射类型为“varchar”而不是“nvarchar”。
///
///
/// 【生成数据库】
///
///
/// 摘要:
/// 该方法把当前程序中实体和属性所定义的约束规则,映射到数据库指定表及其字段上。
///
protected void CreateTable(bool backup = false, int stringDefaultLength = 50)
{
//如果指定的数据库软件中不存在指定的数据库,则自动生成该数据库。
_sqlSugarScope.DbMaintenance.CreateDatabase();
//通过反射操作,获取领域文件夹中的所有实体的类型实例。
//直接获取指定项目中所有类的类型实例。
Assembly assembly = Assembly.Load("Data");
//通过过滤操作,获取领域文件夹中的所有实体的类型实例。
//注意:“Where”过滤操作中“ c.Namespace”最好使用“Contains”,而不要使用“==”。
Type[] _typeArray = assembly.GetTypes()
.Where(c => c.Namespace.Contains("Data.Domain"))//过滤操作。
.ToArray();
if (backup)
{
//如果数据库软件对自动生成的数据库支持自动备份操作,则通过下行语句在自动生成该数据库中,根据当前项目中的实体类自动生成相应的表。
//注意:SetStringDefaultLength(stringDefaultLength)必须定义在下行语句中,否则在自动生成表时,该约束定义将不会被映射到表的字段上。
_sqlSugarScope.CodeFirst.SetStringDefaultLength(stringDefaultLength).BackupTable().InitTables(_typeArray);
}
else
{
//如果数据库软件对自动生成的数据库不支持自动备份操作,则通过下行语句在自动生成该数据库中,根据当前项目中的实体类自动生成相应的表。
//注意:SetStringDefaultLength(stringDefaultLength)必须定义在下行语句中,否则在自动生成表时,该约束定义将不会被映射到表的字段上。
_sqlSugarScope.CodeFirst.SetStringDefaultLength(stringDefaultLength).InitTables(_typeArray);
}
}
#endregion
2.2 关于SqlSugarCore中实体特性的思考
使用“SqlSugarCore”中间件进行开发的开发者们把定义在实体中的形如“[SugarColumn(IsNullable = true, ColumnDataType = "nvarchar", Length = int.MaxValue)]”约束定义标记统称为:“实体特性”,但本人更愿意称它们为约束定义标记。
但是“SqlSugarCore”中间件把实体与“实体特性”标记定义紧密的定义在一起。Entity Framework Core和FluentMigrator中间件同样也可以这么干,二者也可以分离对实体与“实体特性”进行定义,在工程性程序中,这种方式去除了实体,与数据库约束定义之间的耦合,这更加符合软件工程思想中的基本准则,其实在工程性程序中二者也是基本以分离方式对实体与“实体特性”进行定义的。“SqlSugarCore”中间件好像到目前为止不支持这种分离,即使支撑这种分离实现起来也相当的杂,不像:
//设定取消Category与Student之间的级联删除映射定义。
builder.Entity
.WithOne(category => category.GradeSingleton)
.HasForeignKey(category => category.GradeId)
.OnDelete(DeleteBehavior.Restrict);
一样简单,如果有那位读者有“SqlSugarCore”中间件在这方面的实现,请在评论区留言。
3重构HomeController.Index方法
public IActionResult Index()
{
//通过级联操作,获取与成绩相关的所有数据,为页面的渲染显示提供支撑。
List
.Includes(score => score.CourseSingleton)//1层级联
.Includes(
score => score.StudentSingleton,
student => student.SpecialtySingleton)//2层级联
.Includes(
score => score.StudentSingleton,
student => student.CategorySingleton)//2层级联
.Includes(
score => score.StudentSingleton,
student => student.CategorySingleton,
category=> category.GradeSingleton)//3层级联
.ToList();
return View(_scoreList);
}
对以上功能更为具体实现和注释见:22-09-30-04_SqlSugarAcquaintance(初识SqlSugarCore之实体与实体特性)。