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 使用此视图进行插入、更新和删除操作。