在我们的项目中经常采用Model First这种方式先来设计数据库Model,然后通过Migration来生成数据库表结构,有些时候我们需要动态通过实体Model来创建数据库的表结构,特别是在创建像临时表这一类型的时候,我们直接通过代码来进行创建就可以了不用通过创建实体然后迁移这种方式来进行,其实原理也很简单就是通过遍历当前Model然后获取每一个属性并以此来生成部分创建脚本,然后将这些创建的脚本拼接成一个完整的脚本到数据库中去执行就可以了,只不过这里有一些需要注意的地方,下面我们来通过代码来一步步分析怎么进行这些代码规范编写以及需要注意些什么问题。
一 代码分析
/// <summary> /// Model 生成数据库表脚本 /// </summary> public class TableGenerator : ITableGenerator { private static Dictionary<Type, string> DataMapper { get { var dataMapper = new Dictionary<Type, string> { {typeof(int), "NUMBER(10) NOT NULL"}, {typeof(int"NUMBER(10)"}, {typeof(string), "VARCHAR2({0} CHAR)"}, {typeof(bool), "NUMBER(1)"}, {typeof(DateTime), "DATE"}, {typeof(DateTime"DATE"}, {typeof(float), "FLOAT"}, {typeof(float"FLOAT"}, {typeof(decimal), "DECIMAL(16,4)"}, {typeof(decimal"DECIMAL(16,4)"}, {typeof(Guid), "CHAR(36)"}, {typeof(Guid"CHAR(36)"} }; return dataMapper; } } private readonly List<KeyValuePair<string, PropertyInfo _fields = new List<KeyValuePair<string, PropertyInfo(); /// <summary> /// /// </summary> private string _tableName; /// <summary> /// /// </summary> /// <returns></returns> private string GetTableName(MemberInfo entityType) { if (_tableName != null) return _tableName; var prefix = entityType.GetCustomAttribute<TempTableAttribute>() != null "#" : string.Empty; return _tableName = $"{prefix}{entityType.GetCustomAttribute<TableAttribute>()"; } /// <summary> /// 生成创建表的脚本 /// </summary> /// <returns></returns> public string GenerateTableScript(Type entityType) { if (entityType == null) throw new ArgumentNullException(nameof(entityType)); GenerateFields(entityType); const int DefaultColumnLength = 500; var script = new StringBuilder(); script.AppendLine($"CREATE TABLE {GetTableName(entityType)} ("); foreach (var (propName, propertyInfo) in _fields) { if (!DataMapper.ContainsKey(propertyInfo.PropertyType)) throw new NotSupportedException($"尚不支持 {propertyInfo.PropertyType}, 请联系开发人员."); if (propertyInfo.PropertyType == typeof(string)) { var maxLengthAttribute = propertyInfo.GetCustomAttribute<MaxLengthAttribute>(); script.Append($"\t {propName} {string.Format(DataMapper[propertyInfo.PropertyType], maxLengthAttribute"); if (propertyInfo.GetCustomAttribute<RequiredAttribute>() != null) script.Append(" NOT NULL"); script.AppendLine(","); } else { script.AppendLine($"\t {propName} {DataMapper[propertyInfo.PropertyType]},"); } } script.Remove(script.Length - 1, 1); script.AppendLine(")"); return script.ToString(); } private void GenerateFields(Type entityType) { foreach (var p in entityType.GetProperties()) { if (p.GetCustomAttribute<NotMappedAttribute>() != null) continue; var columnName = p.GetCustomAttribute<ColumnAttribute>()"htmlcode">/// <summary> /// Model 生成数据库表脚本 /// </summary> public interface ITableGenerator { /// <summary> /// 生成创建表的脚本 /// </summary> /// <returns></returns> string GenerateTableScript(Type entityType); }这里我们来一步步分析这些部分的含义,这个里面DataMapper主要是用来定义一些C#基础数据类型和数据库生成脚本之间的映射关系。
1 GetTableName
接下来我们看看GetTableName这个函数,这里首先来当前Model是否定义了TempTableAttribute,这个看名字就清楚了就是用来定义当前Model是否是用来生成一张临时表的。
/// <summary> /// 是否临时表, 仅限 Dapper 生成 数据库表结构时使用 /// </summary> [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)] public class TempTableAttribute : Attribute { }具体我们来看看怎样在实体Model中定义TempTableAttribute这个自定义属性。
[TempTable] class StringTable { public string DefaultString { get; set; } [MaxLength(30)] public string LengthString { get; set; } [Required] public string NotNullString { get; set; } }就像这样定义的话,我们就知道当前Model会生成一张SQL Server的临时表。
当然如果是生成临时表,则会在生成的表名称前面加一个‘#'标志,在这段代码中我们还会去判断当前实体是否定义了TableAttribute,如果定义过就去取这个TableAttribute的名称,否则就去当前Model的名称,这里也举一个实例。
[Table("Test")] class IntTable { public int IntProperty { get; set; } public int"htmlcode">public class SqlServerTableGenerator_Tests { [Table("Test")] class IntTable { public int IntProperty { get; set; } public int"IntProperty NUMBER(10) NOT NULL"); sql.ShouldContain("NullableIntProperty NUMBER(10)"); } [Fact] public void GenerateTableScript_TestTableName_Test() { // Act var sql = new TableGenerator().GenerateTableScript(typeof(IntTable)); // Assert sql.ShouldContain("CREATE TABLE Test"); } [TempTable] class StringTable { public string DefaultString { get; set; } [MaxLength(30)] public string LengthString { get; set; } [Required] public string NotNullString { get; set; } } [Fact] public void GenerateTableScript_TempTable_TableNameWithSharp() { // Act var sql = new TableGenerator().GenerateTableScript(typeof(StringTable)); // Assert sql.ShouldContain("Create Table #StringTable"); } [Fact] public void GenerateTableScript_String_Varchar() { // Act var sql = new TableGenerator().GenerateTableScript(typeof(StringTable)); // Assert sql.ShouldContain("DefaultString VARCHAR2(500 CHAR)"); sql.ShouldContain("LengthString VARCHAR2(30 CHAR)"); sql.ShouldContain("NotNullString VARCHAR2(500 CHAR) NOT NULL"); } class ColumnTable { [Column("Test")] public int IntProperty { get; set; } [NotMapped] public int Ingored {get; set; } } [Fact] public void GenerateTableScript_ColumnName_NewName() { // Act var sql = new TableGenerator().GenerateTableScript(typeof(ColumnTable)); // Assert sql.ShouldContain("Test NUMBER(10) NOT NULL"); } [Fact] public void GenerateTableScript_NotMapped_Ignore() { // Act var sql = new TableGenerator().GenerateTableScript(typeof(ColumnTable)); // Assert sql.ShouldNotContain("Ingored NUMBER(10) NOT NULL"); } class NotSupportedTable { public dynamic Ingored {get; set; } } [Fact] public void GenerateTableScript_NotSupported_ThrowException() { // Act Assert.Throws<NotSupportedException>(() => { new TableGenerator().GenerateTableScript(typeof(NotSupportedTable)); }); } }最后我们来看看最终生成的创建表的脚本。
1 定义过TableAttribute的脚本。
CREATE TABLE Test ( IntProperty NUMBER(10) NOT NULL, NullableIntProperty NUMBER(10), )2 生成的临时表的脚本。
CREATE TABLE #StringTable ( DefaultString VARCHAR2(500 CHAR), LengthString VARCHAR2(30 CHAR), NotNullString VARCHAR2(500 CHAR) NOT NULL, )通过这种方式我们就能够在代码中去动态生成数据库表结构了。
以上就是EFCore 通过实体Model生成创建SQL Server数据库表脚本的详细内容,更多关于EFCore 创建SQL Server数据库表脚本的资料请关注其它相关文章!
免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
RTX 5090要首发 性能要翻倍!三星展示GDDR7显存
三星在GTC上展示了专为下一代游戏GPU设计的GDDR7内存。
首次推出的GDDR7内存模块密度为16GB,每个模块容量为2GB。其速度预设为32 Gbps(PAM3),但也可以降至28 Gbps,以提高产量和初始阶段的整体性能和成本效益。
据三星表示,GDDR7内存的能效将提高20%,同时工作电压仅为1.1V,低于标准的1.2V。通过采用更新的封装材料和优化的电路设计,使得在高速运行时的发热量降低,GDDR7的热阻比GDDR6降低了70%。
更新日志
- 群星《2024好听新歌36》AI调整音效【WAV分轨】
- 梁朝伟.1986-朦胧夜雨裡(华星40经典)【华星】【WAV+CUE】
- 方芳.1996-得意洋洋【中唱】【WAV+CUE】
- 辛欣.2001-放120个心【上海音像】【WAV+CUE】
- 柏菲·万山红《花开原野1》限量开盘母带ORMCD[低速原抓WAV+CUE]
- 柏菲·万山红《花开原野2》限量开盘母带ORMCD[低速原抓WAV+CUE]
- 潘安邦《思念精选集全纪录》5CD[WAV+CUE]
- 杨千嬅《千嬅新唱金牌金曲》金牌娱乐 [WAV+CUE][985M]
- 杨钰莹《依然情深》首版[WAV+CUE][1G]
- 第五街的士高《印度激情版》3CD [WAV+CUE][2.4G]
- 三国志8重制版哪个武将智力高 三国志8重制版智力武将排行一览
- 三国志8重制版哪个武将好 三国志8重制版武将排行一览
- 三国志8重制版武将图像怎么保存 三国志8重制版武将图像设置方法
- 何方.1990-我不是那种人【林杰唱片】【WAV+CUE】
- 张惠妹.1999-妹力新世纪2CD【丰华】【WAV+CUE】