在我们的项目中常常回收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>()?.Name ?? entityType.Name}"; } /// <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?.Length ?? DefaultColumnLength)}"); 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>()?.Name ?? p.Name; var field = new KeyValuePair<string, PropertyInfo>(columnName, p); _fields.Add(field); } } }
这里的TableGenerator担任自接口ITableGenerator,在这个接口内部只界说了一个 string GenerateTableScript(Type entityType) 要领。