官方遷移方法: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//然后遷移
