Entity Framework 拦截生成迁移脚本
Entity Framework Intercept Generate Migration Script
我使用 Entity Framework 6.2 Code First (.net framework 4.6.1),我映射了几个实体以通过 Table 属性查看。它适用于 select 操作,我通过编写触发器来处理 Insert/Update/Delete 以在 sql 服务器端查看。它按预期工作,但是当我添加新迁移时,Entity Framework 为使用的 Table 属性生成重命名 Table 脚本(实际上是 EF 的预期行为)。但是我想拦截迁移生成并将这些实体 tableName 更改为原始名称。
我的代码喜欢;
[MapToView("Users","UsersView")]
public class User
{
...
}
我写了MapToView Attribute,这个属性被TableAttribute继承,并传递给TableAttribute的第二个参数。我创建此属性是因为如果我拦截迁移生成,return 原始 table 名称带有此属性参数。
在这种情况下,当我 运行 "add-migration migrationName" 它会创建这样的迁移脚本;
RenameTable(name: "dbo.Users", newName: "UsersView");
但我想在 运行 "add-migration migrationName" 脚本时创建空迁移。
谁能帮帮我?
我解决了问题。
第一:问题是;当我将实体映射到视图时,EF 代码首先使用 ViewName 生成迁移。这是个问题,因为我想使用 View 而不是 Table。所以我用这个说明解决了问题;
1- 我创建了继承自 EntityTypeConfiguration 的 BaseEntityConfiguration 并且所有实体配置 classes 都继承自。
例如:
public class UserConfig: BaseEntityConfiguration<User> //Generic Type is Entity
{
public UserConfig()
{
}
}
2- 我创建由 TableAttribute
继承的 MapToViewAttribute
public class MapToViewAttribute : TableAttribute
{
public string TableName { get; }
public string ViewName { get; }
public MapToViewAttribute(string tableName, string viewName) : base(viewName)
{
TableName = tableName;
ViewName = viewName;
}
}
3- 我使用 MapToViewAttribute 例如用户实体来使用视图。
[MapToView("User","UserView")]
public class User
{
...
}
并且在 BaseEntityConfiguration 的构造函数中,我获得了通用类型和自定义属性。如果任何实体具有 MapToView 属性,我将 TableName 参数传递给 ToTable 方法。因此,在运行时 EF 对这些实体使用 View,但不会为这些实体使用 RenameTable 创建迁移。
protected BaseEntityConfiguration()
{
var baseType = typeof(TEntityType);
var attributes = baseType.GetCustomAttributes(true);
foreach (var attr in attributes)
{
if (attr.GetType() == typeof(MapToViewAttribute))
{
var tableName = ((MapToViewAttribute)attr).TableName;
ToTable(tableName);
}
}
}
最后 EF 不使用您的配置文件,因此您必须告诉 EF 在 DbContext class 的 InternalModelCreate 方法中使用它。
我的实现是这样的;
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
var typesToRegister = Assembly.GetExecutingAssembly()
.GetTypes().Where(IsConfigurationType);
foreach (var type in typesToRegister)
{
dynamic configurationInstance = type.BaseType != null
&& type.BaseType.IsGenericType
&& type.BaseType.GetGenericTypeDefinition() == typeof(BaseEntityConfiguration<>)
? Activator.CreateInstance(type, culture)
: Activator.CreateInstance(type);
modelBuilder.Configurations.Add(configurationInstance);
}
modelBuilder.Types().Configure(t => t.ToTable(t.ClrType.Name));
BaseDbContext.InternalModelCreate(modelBuilder);
}
但是,如果您使用这种方法,则必须创建插入、更新和删除 Triggers/Rule(如果您使用 SQLServer 触发器是一个选项,但如果您使用 postgresql 规则是更好的选项),因为 EF 使用此视图进行插入、更新和删除操作。
我使用 Entity Framework 6.2 Code First (.net framework 4.6.1),我映射了几个实体以通过 Table 属性查看。它适用于 select 操作,我通过编写触发器来处理 Insert/Update/Delete 以在 sql 服务器端查看。它按预期工作,但是当我添加新迁移时,Entity Framework 为使用的 Table 属性生成重命名 Table 脚本(实际上是 EF 的预期行为)。但是我想拦截迁移生成并将这些实体 tableName 更改为原始名称。
我的代码喜欢;
[MapToView("Users","UsersView")]
public class User
{
...
}
我写了MapToView Attribute,这个属性被TableAttribute继承,并传递给TableAttribute的第二个参数。我创建此属性是因为如果我拦截迁移生成,return 原始 table 名称带有此属性参数。
在这种情况下,当我 运行 "add-migration migrationName" 它会创建这样的迁移脚本;
RenameTable(name: "dbo.Users", newName: "UsersView");
但我想在 运行 "add-migration migrationName" 脚本时创建空迁移。
谁能帮帮我?
我解决了问题。 第一:问题是;当我将实体映射到视图时,EF 代码首先使用 ViewName 生成迁移。这是个问题,因为我想使用 View 而不是 Table。所以我用这个说明解决了问题;
1- 我创建了继承自 EntityTypeConfiguration 的 BaseEntityConfiguration 并且所有实体配置 classes 都继承自。 例如:
public class UserConfig: BaseEntityConfiguration<User> //Generic Type is Entity
{
public UserConfig()
{
}
}
2- 我创建由 TableAttribute
继承的 MapToViewAttributepublic class MapToViewAttribute : TableAttribute
{
public string TableName { get; }
public string ViewName { get; }
public MapToViewAttribute(string tableName, string viewName) : base(viewName)
{
TableName = tableName;
ViewName = viewName;
}
}
3- 我使用 MapToViewAttribute 例如用户实体来使用视图。
[MapToView("User","UserView")]
public class User
{
...
}
并且在 BaseEntityConfiguration 的构造函数中,我获得了通用类型和自定义属性。如果任何实体具有 MapToView 属性,我将 TableName 参数传递给 ToTable 方法。因此,在运行时 EF 对这些实体使用 View,但不会为这些实体使用 RenameTable 创建迁移。
protected BaseEntityConfiguration()
{
var baseType = typeof(TEntityType);
var attributes = baseType.GetCustomAttributes(true);
foreach (var attr in attributes)
{
if (attr.GetType() == typeof(MapToViewAttribute))
{
var tableName = ((MapToViewAttribute)attr).TableName;
ToTable(tableName);
}
}
}
最后 EF 不使用您的配置文件,因此您必须告诉 EF 在 DbContext class 的 InternalModelCreate 方法中使用它。 我的实现是这样的;
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
var typesToRegister = Assembly.GetExecutingAssembly()
.GetTypes().Where(IsConfigurationType);
foreach (var type in typesToRegister)
{
dynamic configurationInstance = type.BaseType != null
&& type.BaseType.IsGenericType
&& type.BaseType.GetGenericTypeDefinition() == typeof(BaseEntityConfiguration<>)
? Activator.CreateInstance(type, culture)
: Activator.CreateInstance(type);
modelBuilder.Configurations.Add(configurationInstance);
}
modelBuilder.Types().Configure(t => t.ToTable(t.ClrType.Name));
BaseDbContext.InternalModelCreate(modelBuilder);
}
但是,如果您使用这种方法,则必须创建插入、更新和删除 Triggers/Rule(如果您使用 SQLServer 触发器是一个选项,但如果您使用 postgresql 规则是更好的选项),因为 EF 使用此视图进行插入、更新和删除操作。