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//然后迁移
因缘际会的相遇,自当有非同寻常的结局
QQ交流群:110826636

浙公网安备 33010602011771号