WTM框架在开发过程中如何动态迁移表和创建表

Posted rainbowinthesky

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WTM框架在开发过程中如何动态迁移表和创建表相关的知识,希望对你有一定的参考价值。

官方迁移方法:https://wtmdoc.walkingtec.cn/#/Data/Migration

但是在实际开发过程中使用Add-Migration 方法迁移会发现,把系统内置的表也全部带出来了,自己需要手动删。

在参看官方的源码后发现作者也想到了这个问题(还在开发当中,可以查看EmptyContext),毕竟这不优雅,但是在稳定版本内没有合适的解决方式,故我借鉴了一下(抄袭)。

public partial class EmptyContext : DbContext, IDataContext
    {
        /// <summary>
        /// Commited
        /// </summary>
        public bool Commited { get; set; }

        /// <summary>
        /// IsFake
        /// </summary>
        public bool IsFake { get; set; }

        /// <summary>
        /// CSName
        /// </summary>
        public string CSName { get; set; }

        public DBTypeEnum DBType { get; set; }

        /// <summary>
        /// FrameworkContext
        /// </summary>
        public EmptyContext()
        {
            CSName = "default";
            DBType = DBTypeEnum.SqlServer;
        }

        /// <summary>
        /// FrameworkContext
        /// </summary>
        /// <param name="cs"></param>
        public EmptyContext(string cs)
        {
            CSName = cs;
        }

        public EmptyContext(string cs, DBTypeEnum dbtype)
        {
            CSName = cs;
            DBType = dbtype;
        }

        public IDataContext CreateNew()
        {
            return (IDataContext)this.GetType().GetConstructor(new Type[] { typeof(string), typeof(DBTypeEnum) }).Invoke(new object[] { CSName, DBType });
        }

        public IDataContext ReCreate()
        {
            return (IDataContext)this.GetType().GetConstructor(new Type[] { typeof(string), typeof(DBTypeEnum) }).Invoke(new object[] { CSName, DBType });
        }
        /// <summary>
        /// 将一个实体设为填加状态
        /// </summary>
        /// <param name="entity">实体</param>
        public void AddEntity<T>(T entity) where T : TopBasePoco
        {
            this.Entry(entity).State = EntityState.Added;
        }

        /// <summary>
        /// 将一个实体设为修改状态
        /// </summary>
        /// <param name="entity">实体</param>
        public void UpdateEntity<T>(T entity) where T : TopBasePoco
        {
            this.Entry(entity).State = EntityState.Modified;
        }

        /// <summary>
        /// 将一个实体的某个字段设为修改状态,用于只更新个别字段的情况
        /// </summary>
        /// <typeparam name="T">实体类</typeparam>
        /// <param name="entity">实体</param>
        /// <param name="fieldExp">要设定为修改状态的字段</param>
        public void UpdateProperty<T>(T entity, Expression<Func<T, object>> fieldExp)
            where T : TopBasePoco
        {
            var set = this.Set<T>();
            if (set.Local.AsQueryable().CheckID(entity.GetID()).FirstOrDefault() == null)
            {
                set.Attach(entity);
            }
            this.Entry(entity).Property(fieldExp).IsModified = true;
        }

        /// <summary>
        /// UpdateProperty
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entity"></param>
        /// <param name="fieldName"></param>
        public void UpdateProperty<T>(T entity, string fieldName)
            where T : TopBasePoco
        {
            var set = this.Set<T>();
            if (set.Local.AsQueryable().CheckID(entity.GetID()).FirstOrDefault() == null)
            {
                set.Attach(entity);
            }
            this.Entry(entity).Property(fieldName).IsModified = true;
        }

        /// <summary>
        /// 将一个实体设定为删除状态
        /// </summary>
        /// <param name="entity">实体</param>
        public void DeleteEntity<T>(T entity) where T : TopBasePoco
        {
            var set = this.Set<T>();
            if (set.Local.AsQueryable().CheckID(entity.GetID()).FirstOrDefault() == null)
            {
                set.Attach(entity);
            }
            set.Remove(entity);
        }

        /// <summary>
        /// CascadeDelete
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entity"></param>
        public void CascadeDelete<T>(T entity) where T : TopBasePoco, ITreeData<T>
        {
            if (entity != null && entity.ID != Guid.Empty)
            {
                var set = this.Set<T>();
                var entities = set.Where(x => x.ParentId == entity.ID).ToList();
                if (entities.Count > 0)
                {
                    foreach (var item in entities)
                    {
                        CascadeDelete(item);
                    }
                }
                DeleteEntity(entity);
            }
        }

        /// <summary>
        /// GetCoreType
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public Type GetCoreType(Type t)
        {
            if (t != null && t.IsNullable())
            {
                if (!t.GetTypeInfo().IsValueType)
                {
                    return t;
                }
                else
                {
                    if ("DateTime".Equals(t.GenericTypeArguments[0].Name))
                    {
                        return typeof(string);
                    }
                    return Nullable.GetUnderlyingType(t);
                }
            }
            else
            {
                if ("DateTime".Equals(t.Name))
                {
                    return typeof(string);
                }
                return t;
            }
        }

        /// <summary>
        /// OnModelCreating
        /// </summary>
        /// <param name="modelBuilder"></param>
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {

        }

        /// <summary>
        /// OnConfiguring
        /// </summary>
        /// <param name="optionsBuilder"></param>
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            switch (DBType)
            {
                case DBTypeEnum.SqlServer:
                    try
                    {
                        var Configs = GlobalServices.GetRequiredService<Configs>();
                        if (Configs.IsOldSqlServer == true)
                        {
                            optionsBuilder.UseSqlServer(CSName, op => op.UseRowNumberForPaging());
                        }
                        else
                        {
                            optionsBuilder.UseSqlServer(CSName);
                        }
                    }
                    catch
                    {
                        optionsBuilder.UseSqlServer(CSName, op => op.UseRowNumberForPaging());
                    }
                    break;
                case DBTypeEnum.mysql:
                    optionsBuilder.UseMySql(CSName);
                    break;
                case DBTypeEnum.PgSql:
                    optionsBuilder.UseNpgsql(CSName);
                    break;
                case DBTypeEnum.Memory:
                    optionsBuilder.UseInMemoryDatabase(CSName);
                    break;
                case DBTypeEnum.SQLite:
                    optionsBuilder.UseSqlite(CSName);
                    break;
                case DBTypeEnum.Oracle:
                    optionsBuilder.UseOracle(CSName);
                    break;
                default:
                    break;
            }
            try
            {
                var Configs = GlobalServices.GetRequiredService<Configs>();//如果是debug模式,将EF生成的sql语句输出到debug输出
                if (Configs.IsQuickDebug)
                {
                    optionsBuilder.UseLoggerFactory(LoggerFactory);
                }
            }
            catch { }
            base.OnConfiguring(optionsBuilder);
        }

        public static readonly LoggerFactory LoggerFactory = new LoggerFactory(new[] {
            new DebugLoggerProvider()
        });

        /// <summary>
        /// 数据初始化
        /// </summary>
        /// <param name="allModules"></param>
        /// <param name="IsSpa"></param>
        /// <returns>返回true表示需要进行初始化数据操作,返回false即数据库已经存在或不需要初始化数据</returns>
        public async virtual Task<bool> DataInit(object allModules, bool IsSpa)
        {
            bool rv = await Database.EnsureCreatedAsync();
            return rv;
        }

        #region 执行存储过程返回datatable
        /// <summary>
        /// 执行存储过程,返回datatable结果集
        /// </summary>
        /// <param name="command">存储过程名称</param>
        /// <param name="paras">存储过程参数</param>
        /// <returns></returns>
        public DataTable RunSP(string command, params object[] paras)
        {
            return Run(command, CommandType.StoredProcedure, paras);
        }
        #endregion

        public IEnumerable<TElement> RunSP<TElement>(string command, params object[] paras)
        {
            return Run<TElement>(command, CommandType.StoredProcedure, paras);
        }

        #region 执行Sql语句,返回datatable
        public DataTable RunSQL(string sql, params object[] paras)
        {
            return Run(sql, CommandType.Text, paras);
        }
        #endregion

        public IEnumerable<TElement> RunSQL<TElement>(string sql, params object[] paras)
        {
            return Run<TElement>(sql, CommandType.Text, paras);
        }


        #region 执行存储过程或Sql语句返回DataTable
        /// <summary>
        /// 执行存储过程或Sql语句返回DataTable
        /// </summary>
        /// <param name="sql">存储过程名称或Sql语句</param>
        /// <param name="commandType">命令类型</param>
        /// <param name="paras">参数</param>
        /// <returns></returns>
        public DataTable Run(string sql, CommandType commandType, params object[] paras)
        {
            DataTable table = new DataTable();
            switch (this.DBType)
            {
                case DBTypeEnum.SqlServer:
                    SqlConnection con = this.Database.GetDbConnection() as SqlConnection;
                    SqlDataAdapter adapter = new SqlDataAdapter();
                    using (SqlCommand cmd = new SqlCommand(sql, con))
                    {
                        adapter.SelectCommand = cmd;
                        cmd.CommandTimeout = 2400;
                        cmd.CommandType = commandType;
                        if (paras != null)
                        {
                            foreach (var param in paras)
                                cmd.Parameters.Add(param);
                        }
                        adapter.Fill(table);
                        adapter.SelectCommand.Parameters.Clear();
                    }
                    break;
                case DBTypeEnum.MySql:
                    MySqlConnection mySqlCon = this.Database.GetDbConnection() as MySqlConnection;
                    using (MySqlCommand cmd = new MySqlCommand(sql, mySqlCon))
                    {
                        if (mySqlCon.State == ConnectionState.Closed)
                        {
                            mySqlCon.Open();
                        }
                        cmd.CommandTimeout = 2400;
                        cmd.CommandType = commandType;
                        if (paras != null)
                        {
                            foreach (var param in paras)
                                cmd.Parameters.Add(param);
                        }
                        MySqlDataReader dr = cmd.ExecuteReader();
                        table.Load(dr);
                        dr.Close();
                        mySqlCon.Close();
                    }
                    break;
                case DBTypeEnum.PgSql:
                    Npgsql.NpgsqlConnection npgCon = this.Database.GetDbConnection() as Npgsql.NpgsqlConnection;
                    using (Npgsql.NpgsqlCommand cmd = new Npgsql.NpgsqlCommand(sql, npgCon))
                    {
                        if (npgCon.State == ConnectionState.Closed)
                        {
                            npgCon.Open();
                        }
                        cmd.CommandTimeout = 2400;
                        cmd.CommandType = commandType;
                        if (paras != null)
                        {
                            foreach (var param in paras)
                                cmd.Parameters.Add(param);
                        }
                        Npgsql.NpgsqlDataReader dr = cmd.ExecuteReader();
                        table.Load(dr);
                        dr.Close();
                        npgCon.Close();
                    }
                    break;
                case DBTypeEnum.SQLite:
                case DBTypeEnum.Oracle:
                    var connection = this.Database.GetDbConnection();
                    var isClosed = connection.State == ConnectionState.Closed;
                    if (isClosed)
                    {
                        connection.Open();
                    }
                    using (var command = connection.CreateCommand())
                    {
                        command.CommandText = sql;
                        command.CommandTimeout = 2400;
                        command.CommandType = commandType;
                        if (paras != null)
                        {
                            foreach (var param in paras)
                                command.Parameters.Add(param);
                        }
                        using (var reader = command.ExecuteReader())
                        {
                            table.Load(reader);
                        }
                    }
                    if (isClosed)
                    {
                        connection.Close();
                    }
                    break;
            }
            return table;
        }
        #endregion


        public IEnumerable<TElement> Run<TElement>(string sql, CommandType commandType, params object[] paras)
        {
            IEnumerable<TElement> entityList = new List<TElement>();
            DataTable dt = Run(sql, commandType, paras);
            entityList = EntityHelper.GetEntityList<TElement>(dt);
            return entityList;
        }


        public object CreateCommandParameter(string name, object value, ParameterDirection dir)
        {
            object rv = null;
            switch (this.DBType)
            {
                case DBTypeEnum.SqlServer:
                    rv = new SqlParameter(name, value) { Direction = dir };
                    break;
                case DBTypeEnum.MySql:
                    rv = new MySqlParameter(name, value) { Direction = dir };
                    break;
                case DBTypeEnum.PgSql:
                    rv = new NpgsqlParameter(name, value) { Direction = dir };
                    break;
                case DBTypeEnum.SQLite:
                    rv = new SqliteParameter(name, value) { Direction = dir };
                    break;
                case DBTypeEnum.Oracle:
                    rv = new OracleParameter(name, value) { Direction = dir };
                    break;
            }
            return rv;
        }
    }

  使用的时候

public class DataContext : FrameworkContext
    {
        public DataContext(string cs, DBTypeEnum dbtype)
             : base(cs, dbtype)
        {

        }

    }
    public class MEContext : EmptyContext
    {
        public DbSet<School> Schools { get; set; }
        public MEContext(string cs, DBTypeEnum dbtype)
             : base(cs, dbtype)
        {

        }

    }

    /// <summary>
    /// 为EF的Migration准备的辅助类,填写完整连接字符串和数据库类型
    /// 就可以使用Add-Migration和Update-Database了
    /// </summary>
    public class DataContextFactory : IDesignTimeDbContextFactory<MEContext>
    {
        public MEContext CreateDbContext(string[] args)
        {
            var dc= new MEContext("连接字符串",
                DBTypeEnum.MySql);
            return dc;
        }
    }

然后敲指令

Add-Migration Initia-IgnoreChanges -Context MEContext  //先生成迁移的代码

Update-Database//然后迁移

 

以上是关于WTM框架在开发过程中如何动态迁移表和创建表的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Laravel 项目中删除所有迁移但保留表和字段

WTM

是否可以在 Laravel 7+ 中为已创建的表创建迁移?

abp 框架拓展mysql 迁移:增加数据库表和列备注

如何回滚到以前的迁移并删除架构中的表和列?

如何将ACCESS的表和查询创建成动态的WEB?