public TableChanges(Table oldTable, Table newTable, ChangeType changeType) { this.OldTable = oldTable; this.NewTable = newTable; this.ChangeType = changeType; this.ColumnsChanged = new List<ColumnChanges>(); }
/// <summary> /// Initializes a new instance of the <see cref="Column"/> class. /// </summary> /// <param name="name">列名.</param> /// <param name="dataType">数据类型.</param> /// <param name="length">见 <see cref="Length"/> 属性.</param> /// <param name="table">所在表.</param> /// <exception cref="System.ArgumentNullException"> /// DataTable /// or /// name /// </exception> public Column(string name, DbType dataType, string length, Table table) { if (table == null) throw new ArgumentNullException("DataTable"); if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullException("name"); this.DataType = dataType; this.Length = length; this.Name = name; this.Table = table; }
protected override void LoadAllTables(Database database) { using (var reader = this.Db.QueryDataReader(@"select * from user_tables")) { while (reader.Read()) { string tableName = reader["TABLE_NAME"].ToString(); Table table = new Table(tableName, database); database.Tables.Add(table); } } }
/// <summary> /// 根据实体类型创建表的描述信息,并添加到数据库中 /// </summary> /// <param name="em">The memory.</param> /// <exception cref="System.ArgumentNullException"></exception> /// <exception cref="System.InvalidOperationException">refMeta.ReferenceInfo == null</exception> private void BuildTable(EntityMeta em) { var tableMeta = em.TableMeta; //视图类不需要支持数据库迁移。 if (tableMeta.IsMappingView) { return; } var table = new Table(tableMeta.TableName, this.Database); var metaProperties = em.EntityProperties; //var managedProperties = ManagedPropertyRepository.Instance // .GetTypePropertiesContainer(em.EntityType) // .GetNonReadOnlyCompiledProperties(); foreach (var property in metaProperties) { var columnMeta = property.ColumnMeta; if (columnMeta == null) continue; var mp = property.ManagedProperty; if (mp == null) { throw new ArgumentNullException(string.Format("{0}.{1} 属性需要使用托管属性进行编写。", em.Name, mp.Name)); } //列名 var propertyName = property.Name; var columnName = columnMeta.ColumnName; if (string.IsNullOrWhiteSpace(columnName)) columnName = propertyName; //类型 var propertyType = property.PropertyType; bool isNullableRef = false; #region 引用关系 if (columnMeta.HasFKConstraint) { var refProperty = mp as IRefProperty; if (refProperty != null) { isNullableRef = refProperty.Nullable; var refMeta = em.Property(refProperty.RefEntityProperty); if (refMeta.ReferenceInfo == null) throw new InvalidOperationException("refMeta.ReferenceInfo == null"); //引用实体的类型。 var refTypeMeta = refMeta.ReferenceInfo.RefTypeMeta; if (refTypeMeta != null) { var refTableMeta = refTypeMeta.TableMeta; if (refTableMeta != null) { //如果主键表已经被忽略,那么到这个表上的外键也不能建立了。 //这是因为被忽略的表的结构是未知的,不一定是以这个字段为主键。 if (!this.Database.IsIgnored(refTableMeta.TableName)) { var id = refTypeMeta.Property(Entity.IdProperty); //有时一些表的 Id 只是自增长,但并不是主键,不能创建外键。 if (id.ColumnMeta.IsPrimaryKey) { this._foreigns.Add(new ForeignConstraintInfo() { FkTableName = tableMeta.TableName, PkTableName = refTableMeta.TableName, FkColumn = columnName, PkColumn = id.ColumnMeta.ColumnName, NeedDeleteCascade = refProperty.ReferenceType == ReferenceType.Parent }); } } } } } else if (mp == Entity.TreePIdProperty) { var id = em.Property(Entity.IdProperty); //有时一些表的 Id 只是自增长,但并不是主键,不能创建外键。 if (id.ColumnMeta.IsPrimaryKey) { this._foreigns.Add(new ForeignConstraintInfo() { FkTableName = tableMeta.TableName, PkTableName = tableMeta.TableName, FkColumn = columnName, PkColumn = id.ColumnMeta.ColumnName, NeedDeleteCascade = false }); } } } #endregion var dataType = TypeHelper.IgnoreNullable(propertyType); //对于支持多数据类型的 Id、TreePId 属性进行特殊处理。 if (mp == Entity.IdProperty || mp == Entity.TreePIdProperty) { dataType = em.IdType; } var dbType = columnMeta.DataType.GetValueOrDefault(DbTypeHelper.ConvertFromCLRType(dataType)); var column = new Column(dbType, columnMeta.DataTypeLength, columnName, table); if (columnMeta.IsRequired.HasValue) { column.IsRequired = columnMeta.IsRequired.Value; } else { column.IsRequired = !isNullableRef && !propertyType.IsClass && !TypeHelper.IsNullable(propertyType); } //IsPrimaryKey 的设置放在 IsRequired 之后,可以防止在设置可空的同时把列调整为非主键。 column.IsPrimaryKey = columnMeta.IsPrimaryKey; column.IsIdentity = columnMeta.IsIdentity; table.Columns.Add(column); } table.SortColumns(); this.AddTable(table); }
/// <summary> /// 将表添加到数据库中,对于已经存在的表进行全并 /// </summary> /// <param name="table"></param> private void AddTable(Table table) { var existingTable = this.Database.FindTable(table.Name); if (existingTable != null) { //由于有类的继承关系存在,合并两个表的所有字段。 foreach (var newColumn in table.Columns) { if (existingTable.FindColumn(newColumn.Name) == null) { existingTable.Columns.Add(newColumn); } } } else { this.Database.Tables.Add(table); } }
/// <summary> /// 添加所有表 /// </summary> /// <param name="database"></param> protected override void LoadAllTables(Database database) { using (var reader = this.Db.QueryDataReader(@"select * from INFORMATION_SCHEMA.TABLES")) { while (reader.Read()) { string tableName = reader["TABLE_NAME"].ToString(); string tableType = reader["TABLE_TYPE"].ToString().ToLower(); //SqlServer 中是 "BASE TABLE",同时还会把一些系统表也查询出来,例如:sysdiagrams //SQLCE 中是 "TABLE" if (tableType.Contains("table") && !tableName.StartsWith("sys")) { //string schemaName = reader["SCHEMA_NAME"].ToString(); Table table = new Table(tableName, database); database.Tables.Add(table); } } } }
private string ToEntityName(Table table) { var name = table.Name; if (name.EndsWith("s")) { if (name.EndsWith("aes") || name.EndsWith("oes") || name.EndsWith("ees") || name.EndsWith("ies") || name.EndsWith("ues")) { //支持 es 后缀 name = name.Substring(0, name.Length - 2); } else { //支持 s 后缀 name = name.Substring(0, name.Length - 1); } } return name; }
private void RemoveTable(Table table) { if ((Context.RunDataLossOperation & DataLossOperation.DropTable) != 0) { Context.NotifyDataLoss("删除表"); foreach (var column in table.FindNormalColumns()) { this.RemoveColumn(column); } this.AddOperation(new DropTable { CopyFromTable = table }); } }
private Column RenderId(Table table) { var identites = FindIdentityColumns(table); foreach (var identity in identites) { //这个属性则直接映射 Entity.Id 属性,不需要添加任何代码。 //同时,如果在 Id 字样之前还有其它字母,则需要添加字段映射。 if (identity.Name.ToLower() != "id") { _tablePropertiesConfig.Add(new PropertyConfig { PropertyName = "Id", ColumnName = identity.Name, ClearIdPrimaryKey = !identity.IsPrimaryKey }); } //前面已经用 CheckHasPK 方法进行检测,所以必然有且只有一个字段满足这个条件,直接退出循环。 return identity; } //之前已经用 CheckHasPK 方法检测过,这一行代码不可能到达。 throw new NotSupportedException("未知错误。"); }
private string RenderColumnConfig(Table table) { var code = new StringBuilder(); foreach (var config in _tablePropertiesConfig) { code.AppendFormat(@" Meta.Property({0}.{1}Property).MapColumn().HasColumnName(""{2}"")", ToEntityName(table), config.PropertyName, config.ColumnName ); if (config.ClearIdPrimaryKey) { code.Append(@".IsPrimaryKey(false)"); } code.Append(';'); } return code.ToString(); }
private bool GenerateRepoFile(Table table) { var entityName = ToEntityName(table); var fileName = entityName + "Repository.cs"; var item = _repoDirectory.ProjectItems.FindByName(fileName); if (item != null) return false; _tablePropertiesConfig.Clear(); //使用模板格式化字符串。 var code = ItemCodeTemplate.GetRepositoryFileCode( this.DomainName, this.DomainName + ".Repositories", entityName, _domainBaseEntityName ); //写到文件,并加入到项目中。 var file = Path.Combine(Path.GetDirectoryName(_repoDirectory.get_FileNames(1)), fileName); File.WriteAllText(file, code); _repoDirectory.ProjectItems.AddFromFile(file); return true; }
private bool GenerateClassFile(Table table) { if (table.Name == "zzzDbMigrationVersion") return false; var entityName = ToEntityName(table); var fileName = entityName + ".cs"; var item = _directory.ProjectItems.FindByName(fileName); if (item != null) return false; if (!CheckHasPK(table)) return false; _tablePropertiesConfig.Clear(); var parameters = new ItemCodeTemplate.EntityFileCodeParamters() { domainNamespace = this.DomainName, domainEntityName = entityName, domainBaseEntityName = _domainBaseEntityName, }; //生成属性、引用属性 parameters.normalProperties = this.RenderNormalProperties(table); parameters.refProperties = this.RenderRefProperties(table); parameters.tableConfig = entityName == table.Name ? "Meta.MapTable().MapAllProperties();" : string.Format(@"Meta.MapTable(""{0}"").MapAllProperties();", table.Name); parameters.columnConfig = this.RenderColumnConfig(table); //使用模板格式化字符串。 var code = ItemCodeTemplate.GetEntityFileCode(parameters); //写到文件,并加入到项目中。 var file = Path.Combine(Path.GetDirectoryName(_directory.get_FileNames(1)), fileName); File.WriteAllText(file, code); _directory.ProjectItems.AddFromFile(file); return true; }
private IEnumerable<Column> FindIdentityColumns(Table table) { foreach (var column in table.Columns) { if (column.IsIdentity) { var columnNameLower = column.Name.ToLower(); if (columnNameLower.EndsWith("id")) { yield return column; } } } }
private bool CheckHasPK(Table table) { //以下情况必须抛出异常,详情见:RenderNormalProperties 方法。 var identites = FindIdentityColumns(table); var count = identites.Count(); if (count != 1) { if (count == 0) { AddError(string.Format("{0} 表中没有自增、命名以 Id 结尾的整形列。", table.Name)); } else { AddError(string.Format("{0} 表中自增长、命名并以 Id 结尾的整形列过多。", table.Name)); } return false; } return true; }
public void DMT_CreateTable() { this.Test(destination => { var tmpTable = new Table("TestingTable", destination); tmpTable.AddColumn("Id", DbType.Int32, isPrimaryKey: true); tmpTable.AddColumn("Name", DbType.String); destination.Tables.Add(tmpTable); }, result => { var tmpTable2 = result.FindTable("TestingTable"); Assert.IsTrue(tmpTable2 != null); Assert.IsTrue(tmpTable2.Columns.Count == 2); }); }
/// <summary> /// 计算出新旧表之间的数据列差别 /// </summary> /// <param name="oldTable">旧表</param> /// <param name="newTable">新表</param> /// <returns> /// 返回表之间区别,如果没有区别,则返回null /// </returns> private static TableChanges Distinguish(Table oldTable, Table newTable) { //if (newTable == null) throw new ArgumentNullException("newTable"); //if (oldTable == null) throw new ArgumentNullException("oldTable"); //if (newTable.Name != oldTable.Name) throw new InvalidOperationException("newTable.Name != oldTable.Name must be false."); var record = new TableChanges(oldTable, newTable, ChangeType.Modified); //先找到已经删除的列 foreach (var oldColumn in oldTable.Columns) { if (newTable.FindColumn(oldColumn.Name) == null) { record.ColumnsChanged.Add(new ColumnChanges(oldColumn, null, ChangeType.Removed)); } } //记录新增的和更改过的列 foreach (var column in newTable.Columns) { Column oldColumn = oldTable.FindColumn(column.Name); if (oldColumn == null) { var columnChanged = new ColumnChanges(null, column, ChangeType.Added); record.ColumnsChanged.Add(columnChanged); } else { var columnChanged = Distinguish(oldColumn, column); //新增的 或者 修改的 列 if (columnChanged != null) { record.ColumnsChanged.Add(columnChanged); } } } //如果被修改了,则返回record;否则返回null if (record.ColumnsChanged.Count > 0) { return record; } return null; }
private string RenderNormalProperties(Table table) { var code = new StringBuilder(); //先输出 Id 字段。 var idColumn = RenderId(table); //Id 字段以外的其它字段,都可以输出了。 foreach (var column in table.Columns) { if (!column.IsForeignKey && column != idColumn) { string propertyType = string.Empty; #region 转换到属性的类型 switch (column.DataType) { case DbType.AnsiString: case DbType.AnsiStringFixedLength: case DbType.StringFixedLength: case DbType.Xml: case DbType.String: propertyType = "string"; break; case DbType.Int16: case DbType.Int32: case DbType.Int64: case DbType.SByte: case DbType.UInt16: case DbType.UInt32: case DbType.UInt64: propertyType = "int"; if (!column.IsRequired) propertyType += '?'; break; case DbType.VarNumeric: case DbType.Single: case DbType.Double: propertyType = "double"; if (!column.IsRequired) propertyType += '?'; break; case DbType.Decimal: propertyType = "decimal"; if (!column.IsRequired) propertyType += '?'; break; case DbType.Date: case DbType.DateTime: case DbType.DateTime2: case DbType.DateTimeOffset: case DbType.Time: propertyType = "DateTime"; if (!column.IsRequired) propertyType += '?'; break; case DbType.Boolean: propertyType = "bool"; if (!column.IsRequired) propertyType += '?'; break; case DbType.Binary: propertyType = "byte[]"; break; case DbType.Byte: propertyType = "byte"; break; case DbType.Guid: propertyType = "Guid"; if (!column.IsRequired) propertyType += '?'; break; case DbType.Object: case DbType.Currency: default: propertyType = "string"; break; } #endregion var propertyCode = ItemCodeTemplate.GetNormalPropertyCode(ToEntityName(table), propertyType, column.Name); code.Append(propertyCode); } } return code.ToString(); }
private string RenderRefProperties(Table table) { var code = new StringBuilder(); foreach (var column in table.Columns) { if (column.IsForeignKey) { //如果属性名以 Id 结尾,则直接去除 Id 即可。 //否则,映射失败,直接以列名作为引用属性的名称,添加列名 + Id 与属性名的映射。 string propertyName = string.Empty; var columnName = column.Name; if (columnName.ToLower().EndsWith("id")) { propertyName = columnName.Substring(0, columnName.Length - 2); } else { propertyName = columnName; } //处理一些类似于 RefEntity_Id 的字段,去掉最后的下划线。 while (propertyName[0] == '_') { propertyName = propertyName.Substring(1); } while (propertyName[propertyName.Length - 1] == '_') { propertyName = propertyName.Substring(0, propertyName.Length - 1); } //如果字段与属性名不同,需要添加属性的配置。 var idProperty = propertyName + "Id"; if (!idProperty.EqualsIgnoreCase(columnName)) { _tablePropertiesConfig.Add(new PropertyConfig { PropertyName = idProperty, ColumnName = columnName }); } var refEntity = ToEntityName(column.ForeignConstraint.PKTable); var propertyCode = ItemCodeTemplate.GetRefPropertyCode( ToEntityName(table), refEntity, propertyName, isRequired: column.IsRequired ); code.Append(propertyCode); } } return code.ToString(); }
private void AddTable(Table table) { var op = new CreateTable() { CopyFromTable = table }; this.AddOperation(op); foreach (var column in table.FindNormalColumns()) { this.AddColumn(column); } }