If EF migration decides to rename a column (or a table), it fulfills this by dropping the (old) column and then adding a column with the new name. This clearly leads to data loss.
Is there any way to prevent EF migration from dropping a column and force it to use RenameColumn instead?
Well, I didn't find a clear and straightforward solution.
My solution is hiding DbMigration class which every migration that was generated using code-based migration is derived from. I do this by introducing a new class with the same name (DbMigration). Then I put it inside the same assembly and same namespace where code files reside. This way, any reference of code files to the original DbMigration resolves to the new DbMigration type. Then, I can switch dropping a column ON or Off:
namespace MyProject.DAL.Migrations
{
/// <summary>
/// Customized DbMigration which protects columns to be dropped accidentally
/// </summary>
public abstract class DbMigration : global::System.Data.Entity.Migrations.DbMigration
{
public bool AlloDropColumn { get; set; }
protected internal new void DropColumn(string table, string name, object anonymousArguments = null)
{
if (!AlloDropColumn)
throw new Exception("MyProject: Dropping a column while updating database is prohibited. If you really want to drop column(s), set property 'AllowDropColumn' true.");
}
}
}
And in a code file:
public partial class _1 : DbMigration
{
public override void Up()
{
AlloDropColumn = true; // To allow column drop
AddColumn("driver.TruckDriver", "FullName2", c => c.String());
DropColumn("driver.TruckDriver", "FullName");
}
public override void Down()
{
AddColumn("driver.TruckDriver", "FullName", c => c.String());
DropColumn("driver.TruckDriver", "FullName2");
}
}
Related
i've a model like that
public class Class1 {
public int identifier {get;set;}
}
public class Class2 {
public int identifier {get;set;}
public List<Class1> holders {get;set;}
public List<Class1> users{get;set;}
}
my problem is the generated foreign keys in Class1 name are "Class2_identifier" and "Class2_identifier1" mean while what i want is "Class2_holders_identifier" and "Class2_users_identifier"
the real model is really huge so what i'm looking for is away to override how the names are generated in the "add-migration" step
Not a complete implementation, just a hint: If you are using EntityFramework 6 you can define a custom model convention:
public class ForeignKeyNamingConvention : IStoreModelConvention<AssociationType>
{
public void Apply(AssociationType association, DbModel model)
{
if (association.IsForeignKey)
{
var constraint = association.Constraint;
// Implement your renaming code.
// The data you need is inside association.Constraint.
}
}
}
And add it to your DbContext.OnModelCreating:
modelBuilder.Conventions.Add(new ForeignKeyNamingConvention());
This answer contains some code that you can reuse (in this case the convention is used to remove underscores in the column names).
Edit: OP included their final solution here:
The problem as mentioned in ef core "it's the same problem in ef6 but with no message" console
There are multiple relationships between 'Class1' and 'Class2' without configured foreign key properties causing EF to create shadow properties on 'Organization' with names dependent on the discovery order.
public class ForeignKeyNamingConvention : IStoreModelConvention<AssociationType>
{
public void Apply(AssociationType association, DbModel model)
{
if (association.IsForeignKey)
{
var constraint = association.Constraint;
// as i just needed the fk column name to be more clear
// "{entityName}_{propertyName}" which is provided in
// {association.Name}
association.Constraint.ToProperties[0].Name = association.Name;
}
}
}
I would like to add a VIEW to the database, and query the data from this VIEW using L2E. I use migrations for maintaining database schema.
I added one class that should MAP to a VIEW columns. As an example, this class has only two properties
[Table("View_Data")]
public class ViewData
{
[Key]
public int Id { get; set; }
public int PropertyA { get; set; }
}
public class ViewDataMap : EntityTypeConfiguration<ViewData>
{
public ViewDataMap ()
{
this.ToTable("View_Data");
this.HasKey(t => t.Id);
}
}
I added ViewDataMap to OnModelCreating, as with any other Table mappings. I added DbSet ViewDatas.
When I executed
add-migration preview
it created new migration with CreateTable command. Since I do not want to create a table, but only a view, I replaced in UP() CreateTable with Sql("CREATE VIEW...")
Still, EF complains about pending changes in database, and still wants to create new migration with CreateTable()...
How can prevent EF to create new table, but use VIEW instead?
As Steve suggested in the comment, I forgot to do update-database, then all works as expected.
Is it possible to change table name "__MigrationsHistory" when using codefIrst?
Problem: I am using Oracle Database and I have rules to create new tables. One of them is that there can not be any table names or fields with special characters.
Refer this Link - Is changing the name of the EF __Migration History table dangerous?
This will explain on how to rename the database and what should be done.
This is a bit late but, could help someone who struggle having multiple DBContexts using the same DB scheme.
In order to rename __MigrationHistory table; create a custom class that implements HistoryContext class and override parents OnModelCreating method. Then create a custom configuration class, pass our custom HistoryContext with SetDefaultHistoryContext method.
Please take a look at System.Data.Entity.Migrations.History.HistoryContext
A custom HistoryContext class;
public class YourHistoryContext : HistoryContext
{
public YourHistoryContext(System.Data.Common.DbConnection dbConnection, string defaultSchema)
: base(dbConnection, defaultSchema)
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<HistoryRow>().ToTable(tableName: "YourCustomMigrationHistory"/*, schemaName: "dbo__OrYourCustomScheme"*/);
//Rename Id column name.
//modelBuilder.Entity<HistoryRow>().Property(p => p.MigrationId).HasColumnName("Migration_ID");
}
}
Create a custom DbConfiguration class;
public class MigrationHistoryConfiguration : DbConfiguration
{
public MigrationHistoryConfiguration()
{
//this.SetHistoryContext("System.Data.SqlClient",
// (connection, defaultSchema) => new HistoryContext(connection, defaultSchema));
this.SetDefaultHistoryContext((connection, defaultSchema) => new YourHistoryContext(connection, defaultSchema));
}
}
The Problem
We have an object
public class Foo
{
[Key, Column(Order = 0)]public virtual int A { get; set; }
[Key, Column(Order = 1)]public virtual int B { get; set; }
}
that needs to be mapped to an indexed view in SQL Server. Building on the approaches
EF Code First : Mapping nontable objects with Fluent API and https://stackoverflow.com/a/20887064/141172
we first created an initial migration
public override void Up()
{
CreateTable("dbo.Foos",
c => new { A = c.Int(nullable:false), B = c.Int(nullable:false) })
.PrimaryKey(t => new { t.A, t.B });
}
Then an empty migration into which we added SQL to drop the auto-generated table, and then add the index
public override void Up()
{
Sql(#"DROP TABLE Foos");
Sql(#"CREATE VIEW dbo.Foos As....");
}
finally in our DbContext, Foo is mapped to the view:
modelBuilder.Entity<Foo>().ToTable("Foos");
This worked just fine, until we added another property to Foo:
[Key, Column(Order = 2)]public int C { get; set; }
We added a new migration to redefine the view
public override void Up()
{
Sql(#"ALTER VIEW Foos ....");
}
The Alter View migration is correctly applied, but EF believes that it must create a migration to account for the new property.
Unable to update database to match the current model because there are pending changes and automatic migration is disabled. Either write the pending model changes to a code-based migration or enable automatic migration.
When I run
Add-Migration WhatIsPending
EF generates
public override void Up()
{
DropPrimaryKey("dbo.Foos");
AddColumn("dbo.Foos", "C", c => c.Int(nullable: false));
AddPrimaryKey("dbo.Foos", new[] {"A", "B", "C" });
}
Question
Is there a better approach to mapping an object to a view, such that changes to the object are painless?
If this is the best approach, how can I inform EF Migrations that it does not need to generate the migration?
We couldn't find a way to tell EF to not create a migration, but this approach might help:
When you create the POCO, don't CreateTable() in the migration. if EF wants to create a migration file, fine, but you can comment the code out so only your Sql(#"Create View ..."); runs.
All we had to do then was create the DbSet for the view, not a modelBuilder.Entity entry.
When you need to make changes, start the same way as any other table. Make changes to the POCO, then run Add-Migration and let it create the migration for you. comment out whatever it wants to do, and add your Alter View script in. make sure you make a corresponding one in the Down.
This way you will just have a single migration file for each change.
I am using EF CF approach for a website with MySQL.
For some reason EF creates a column in my Post table called "Discriminator" and contains the VARCHAR "Post".
Why is this column created? Can I do something to avoid it being created? Are there any advantages of having this column?
The Discriminator column is used and required in Table-Per-Hierarchy inheritance scenarios. If you for example have a model like this ...
public abstract class BaseEntity
{
public int Id { get; set; }
//...
}
public class Post : BaseEntity
{
//...
}
public class OtherEntity : BaseEntity
{
//...
}
... and make the BaseEntity part of the model, for instance by adding a DbSet<BaseEntity> to your derived context, Entity Framework will map this class hierarchy by default into a single table, but introduce a special column - the Discriminator - to distinguish between the different types (Post or OtherEntity) stored in this table. This column gets populated with the name of the type (again Post or OtherEntity).
You can stop the column being created by adding the [NotMapped] data annotation to the models that are inheriting from your base class. This will tell EF not to add your class to future migrations, removing the discriminator column.
public class BaseClass
{
}
[NotMapped]
public class InheritingClass : BaseClass
{
}
For completeness, if you want to use the fluent API to stop the inheriting class from being mapped with entity (and therefore stopping the discriminator column being created) you can do the following:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Ignore<InheritingClass>();
}