Ejemplo n.º 1
0
        /// <summary>
        /// 尝试同步表,有可能不成功
        /// </summary>
        /// <param name="table"></param>
        private void SyncTable(ITableContext table)
        {
            bool hasRow = this.TableHasRow(table.Name);

            //表肯定存在,就看列存不存在
            //最简单的迁移策略:
            //如果列在表里不存在就建,以用户定义的为准
            //列元属性同步策略:
            //* 类型相同可以更改长度,其实也就是 varchar 可以
            //* 可空转非空:检测表里是否有行,有的话要求此字段有默认值,更改之前先用默认值填充
            //  现有行再转换为非空
            //* 非空转可控:可以直接去掉 NOT NULL
            //先处理代码里定义的列
            foreach (var pair in this.model.Fields)
            {
                var field = pair.Value;
                if (field.IsColumn)
                {
                    if (!table.ColumnExists(field.Name))
                    {
                        table.AddColumn(this.context.DataContext, field);
                    }
                    else
                    {
                        this.SyncColumn(table, field, hasRow);
                    }
                }
            }

            //然后处理数据库里存在,但代码里未定义的列
            //处理策略很简单,我们的原则是不能删除用户的数据,如果是空表直接删除该列,如果有数据就把该列设成可空
            var columns         = table.GetAllColumns();
            var columnsToDelete = columns.Select(c => c.Name)
                                  .Except(this.model.Fields.Select(f => f.Value.Name));

            //删除数据库存在,但代码未定义的

            if (hasRow)
            {
                foreach (var c in columns)
                {
                    if (!c.Nullable && columnsToDelete.Contains(c.Name))
                    {
                        table.AlterColumnNullable(this.context.DataContext, c.Name, true);
                    }
                }
            }
            else
            {
                foreach (var c in columnsToDelete)
                {
                    table.DeleteColumn(this.context.DataContext, c);
                }
            }
        }