0

I use Entity Framework 6.2 Code First (.net framework 4.6.1) and I map few entities to view via Table Attribute. It works for select operations and I handle Insert/Update/Delete with writing trigger to view at sql server side. It works as expected, however when I add a new migration, Entity Framework generate RenameTable scripts for used Table Attribute (actuallyis expected behavior for EF). But I want to intercept migration generation and change these entities tableName to original name.

my code like;

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

I wrote MapToView Attribute, this attribute inherited by TableAttribute and pass to second parameter to TableAttribute. I create this Attribute because if I intercept migration generation, return original table name with this attribute parameters.

In this case when I run "add-migration migrationName" it creates migration scripts like this;

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

but i want to create empty migration when I run "add-migration migrationName" script.

anyone can help me?

4
  • It's unusual to use views and not have a database-first workflow. Commented Dec 3, 2018 at 14:45
  • yes, i know but i need it. because i have to get data from view but insert, update or delete operation in real table. So I use Table Attribute to change table name to view but this time insert, update and delete queries also map to view, then i wrote triggers for them but i can not figure out how to intercept ef's generating migrations and how to change table name view to real table name for migration scripts. Commented Dec 3, 2018 at 19:15
  • Right. So I'm suggesting that you stop using migrations. And instead manage the database schema directly, switching to a database-first workflow. Commented Dec 3, 2018 at 19:31
  • Hi @DavidBrowne-Microsoft I solve problem and post answer how to. I know this isn't efficent way but it works. Thanks for your commens. Commented Dec 4, 2018 at 7:57

1 Answer 1

2

I solve the problem. First: Problem is; When I Map Entity to View EF Code-first generate migration with ViewName. This is problem because I want to use View Instead of Table. So I solve problem with this instructions;

1- I Create BaseEntityConfiguration that Inherited from EntityTypeConfiguration and all entity configuration classes are inherited by. for example:

public class UserConfig: BaseEntityConfiguration<User> //Generic Type is Entity
    {
        public UserConfig()
        {
        }
    }

2- I Create MapToViewAttribute that inherited by TableAttribute

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- I Use MapToViewAttribute for example User Entity to use View.

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

And in BaseEntityConfiguration's Constructor I Get Generic Type and custom attributes. If any entity has MapToView Attribute, I pass to TableName parameter to ToTable Method. So at runtime EF uses View for these entities but doesn't create migration with RenameTable for these entities.

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);
                }
            }
        }

Last EF don't use your configuration files, so you must tell the EF to use this in DbContext class's InternalModelCreate method. My implementation like this;

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);
        }

But if you use this approach you must create Insert, Update and Delete Triggers/Rule (if you use SQLServer trigger is an option but if you use postgresql rule is better option) because EF uses this view for insert, update and delete operations.

Sign up to request clarification or add additional context in comments.

1 Comment

My problem is a bit different and I still cannot find the solution: I need to modify migration script output: remove quotes around table and column names, etc. Unfortunately, DbCommandInterceptor is not applicable in this case... It's just speaking aloud - I know you don't use DbCommandInterceptor :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.