实体框架拦截生成迁移脚本

时间:2018-12-03 08:08:32

标签: entity-framework entity-framework-6 ef-migrations

我使用实体框架6.2代码优先(.net框架4.6.1),并且我映射了几个实体以通过表属性进行查看。它适用于选择操作,我通过编写触发器来处理插入/更新/删除操作,以在sql服务器端进行查看。它可以按预期工作,但是当我添加新迁移时,实体框架会为使用的表属性生成RenameTable脚本(实际上是EF的预期行为)。但是我想拦截迁移生成,并将这些实体tableName更改为原始名称。

我的代码如下;

[MapToView("Users","UsersView")]
public class User
{
...
}

我写了MapToView Attribute,此属性由TableAttribute继承,并传递给TableAttribute的第二个参数。之所以创建此属性,是因为如果我拦截了迁移的生成,请使用此属性参数返回原始表名。

在这种情况下,当我运行“ add-migration migrationName”时,它将创建这样的迁移脚本;

RenameTable(name: "dbo.Users", newName: "UsersView");

但是我想在运行“ add-migration migrationName”脚本时创建空迁移。

有人可以帮助我吗?

1 个答案:

答案 0 :(得分:2)

我解决了这个问题。 第一:问题在于;当我将实体映射到View EF Code-first时,会使用ViewName生成迁移。这是问题,因为我想使用“视图”而不是“表”。因此,我使用此说明解决了问题;

1-我创建了从EntityTypeConfiguration继承的BaseEntityConfiguration和所有实体配置类。 例如:

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例如用户实体来使用View。

 [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类的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);
        }

但是,如果使用这种方法,则必须创建插入,更新和删除触发器/规则(如果使用SQLServer触发器是一个选项,但是如果使用postgresql规则则更好),因为EF使用此视图进行插入,更新和删除操作。