I'm using Oracle's Entity Framework 12.1.22 (6.121.2.0) and Entity Framework 6.0.0.
I have a custom HistoryContext that ensures the __MigrationHistory table is in the same schema as the rest of the model, because we have multiple applications using the same database.
When I start from scratch and run Update-Database from the Package Manager Console, everything appears to work fine, and the __MigrationHistory table is exactly where I expect it to be. However, it quickly becomes obvious there's a problem:
PM> Update-Database -TargetMigration:0
Specify the '-Verbose' flag to view the SQL statements being applied to the target database.
Target database is already at version 0.
PM> Add-Migration 2
Unable to generate an explicit migration because the following explicit migrations are pending: [201601221958588_1]. Apply the pending explicit migrations before attempting to generate a new explicit migration.
PM> Get-Migrations
Retrieving migrations that have been applied to the target database.
No migrations have been applied to the target database.
The problem is that Get-Migrations is not looking in the correct schema for the __MigrationHistory table - it's looking in the user schema for the user named in the connection string. I verified this by creating a copy of the __MigrationHistory table there, at which point all of the above commands began to work as expected.
Can anyone point out what I'm doing wrong?
public class MyContext : DbContext
{
public MyContext()
: base("name=Blue")
{
}
public virtual DbSet<MyEntity> MyEntities { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.HasDefaultSchema("BLUE");
}
}
public class MyEntity
{
[Key, MaxLength(80)]
public string Name { get; set; }
}
public class MyDbConfiguration : DbConfiguration
{
public MyDbConfiguration()
{
this.SetHistoryContext("Oracle.ManagedDataAccess.Client",
(connection, defaultSchema) => new MyHistoryContext(connection, defaultSchema));
}
}
public class MyHistoryContext : HistoryContext
{
public MyHistoryContext(DbConnection dbConnection, string defaultSchema)
: base(dbConnection, defaultSchema)
{
this.defaultSchema = defaultSchema;
}
private string defaultSchema;
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.HasDefaultSchema(this.defaultSchema);
}
}
I used the instructions here: Customizing the Migrations History Table (EF6 onwards)
Related
I added an entity class to my EF Core 5.0/MS SQL Server data model that is backed by a defining query (raw SQL query, with no table or view corresponding to it in my database).
When I make changes to it (for example, adding a new column) and then run Add-Migration in Package Manager Console to create a migration step, it generates a migration with empty Up(MigrationBuilder migrationBuilder) and Down(MigrationBuilder migrationBuilder) methods. But the generated [MigrationName].Designer.cs file contains the new column, and the ModelSnapshot for my DbContext gets modified to include the new columns, so something has changed.
My question is, do I need to add a migration each time I make a change to one of these entities in order for my app to function properly? If they're not needed, what is considered better practice when I update the defining query -backed entity:
A. Adding these migrations even though they have blank Up(MigrationBuilder migrationBuilder) and Down(MigrationBuilder migrationBuilder) methods, because the model changed, or
B. Not generating the migration and just having these changes get picked up the next time someone makes a change that actually impacts the underlying database structures?
Code snippets (over-simplified to remove identifying data):
Entity class
public class Thing
{
public int Id { get; set; }
public string Name { get; set; }
}
Entity Configuration:
public class ThingTypeConfiguration : IEntityTypeConfiguration<Thing>
{
public void Configure(EntityTypeBuilder<Thing> builder)
{
builder
.HasNoKey()
.ToView("Dummy") // This is here to work around an issue with the migrations auto-generating a table for the entity - see https://github.com/dotnet/efcore/issues/19972
.ToSqlQuery(
#"SELECT
[TableName].[IdColumn] AS Id,
[TableName].[OtherColumn] AS Name
FROM
[TableName]");
}
}
DbContext:
public class MyDbContext : DbContext
{
public MyDbContext()
{
}
public MyDbContext(DbContextOptions<MyDbContext> options)
: base(options)
{
}
public virtual DbSet<Thing> Things { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfigurationsFromAssembly(typeof(MyDbContext).Assembly);
}
}
Examples of Migration partial classes that get generated:
Partial class with empty Up/Down methods:
public partial class MyMigration : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
}
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}
Auto-generated __.Designer.cs file (the rest of the class):
[DbContext(typeof(MyDbContext))]
[Migration("20210302175116_MyMigration")]
partial class MyMigration
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("ProductVersion", "5.0.3")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
/* Entity configuration logic for all the other entities in my model.. */
modelBuilder.Entity("MyDataProject.Thing", b =>
{
b.Property<string>("Id")
.HasColumnType("int");
b.Property<string>("Name")
.HasColumnType("nvarchar(max)");
b.ToView("Dummy");
b
.HasAnnotation("Relational:SqlQuery", "/* My SQL query */");
});
#pragma warning restore 612, 618
}
}
No. If the database schema hasn't changed, you don't need to add a new migration.
Heck, you don't even really need to add a new migration if the new schema is compatible with the old one. For example, removing an optional property would still be compatible.
The *.Designer file is just there to occasionally provide additional information about the model when generating SQL. And, Since the migration doesn't generate SQL, it's entirely unused in this case.
I have simple context with 3 tables.
database tables are already present but using code first approach.
Model Device.cs is -
public class Device
{
public System.Guid Id { get; set; }
public string Name{ get; set; }
}
public class sampledbContext : DbContext
{
public sampledbContext ()
: base("name=sampledbContext ")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
public virtual DbSet<Device> Devices { get; set; }
}
To avoid extra s I have added above line into OnModelCreating but it is giving an error -
System.InvalidOperationException: 'The model backing the 'sampledbContext' context has changed since the database was created. Consider using Code First Migrations to update the database (http://go.microsoft.com/fwlink/?LinkId=238269).'
Database was already created and I try to use code first approach here.
I have not done update-database yet.
I tried doing Enable-Migration and Update-database it creates table with name s like Devices why ? s is added ?
You've turned off auto-migrations in the line:
Database.SetInitializer<IoTSimulatordbContext>(null);
And therefore you will need to run update-database manually to update the model (you can run this via package manager console). If you have any data in your tables it is likely that the migration will fail due to the possibility of losing data, in that case you will need to either delete all data from the tables first or make a custom migration script to handle copying the data first. As this seems like a test it may be better to restart the migration project with the pluralisation off from the beginning.
You can add a DataAnnotation to describe the Schema and Table name to your Table class such as this;
[Table("Device", Schema = "MySchema")]
This will give you more control over the naming.
I'm learning about Entity Framework and I want to create a project with it. I've use FluentNhibernate in my project but now I want to try Entity, but I have a doubt about how to create all tables(DBSet) when the application is loading. In my case I have 3 tables: Cliente, Produto, Venda, that I want to create when application is loading but I don't know how to do this.
How could I do this ?
trying
[DbConfigurationType(typeof(MySql.Data.Entity.MySqlEFConfiguration))]
public class DatabaseContext : DbContext{
public DatabaseContext():base("default"){
Database.SetInitializer<DatabaseContext>(new CreateDatabaseIfNotExists<DatabaseContext>());
//Database.CreateIfNotExists();
}
public DbSet<Cliente> clientes { get; set; }
public DbSet<Produto> produtos { get; set; }
public DbSet<Venda> vendas { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder){
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<Produto>()
.Property(p => p.valor)
.HasPrecision(9,2); // or whatever your schema specifies
Database.SetInitializer<DatabaseContext>(null);
base.OnModelCreating(modelBuilder);
}
}
Assuming you already have all your DbContext and Entities setup and you are just asking about generating/updating the database, you are looking for Entity Framework's migration features.
Open Package Manager Console and run the following commands in your project:
// Enable migrations to your project
Enable-Migrations
// Add migrations to your project
Add-Migration
// Update any changes to the generated database
Update-Database
More details here:
https://martinnormark.com/entity-framework-migrations-cheat-sheet/
In the OnModelCreating method remove:
Database.SetInitializer<DatabaseContext>(null);
i suggest you to read:
http://www.entityframeworktutorial.net/code-first/database-initialization-strategy-in-code-first.aspx
and about automatic migration:
http://www.entityframeworktutorial.net/code-first/automated-migration-in-code-first.aspx
I have a site. using COde first. My add-migration command producted following code.
public partial class StudentEntity : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.Student",
c => new
{
id = c.Int( nullable: false, identity: true),
name = c.String(),
})
.PrimaryKey(t => t.id);
}
Now I want to deploy my site so when site runs the first time I want the Student table to get generated in DB(SQL server).
Right now when I run the site it does not create any table. How can I do this? I dont want any seed data to initialize with
My db context class
public partial class flagen:DbContext
{
public flagen() : base("name=cf2")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
//old entity
public virtual DbSet<flag> flags { get; set; }
//new entity
public virtual DbSet<Student> students { get; set; }
}
Then I tried to use Context so table get created. It throws error "The model backing the 'flagen' context has changed since the database was created. Consider using Code First Migrations to update the database "
The I added following two lines to dbcontext class
Database.SetInitializer<flagen>(null);
base.OnModelCreating(modelBuilder);
now it says "invalid object name students"
any solution that works?
One solution could be to define a Initializer that will migrate your database to last existing migration you added. Therefore all tables will be created and the Seed method of the Configuration will be executed too - you could use it for seeding data.
With the following example your database will be updated to last existing migration (and therefore creates all tables) on first initialization of the data context. (var dbContext = new MyDatabaseContext())
In my opinion a much cleaner way than to use AutomaticMigrationsEnabled = true that you could check out too. ;)
As mentioned here is an example that will use the MigrateDatabaseToLatestVersion initializer with the defined behavior.
public partial class MyDatabaseContext : DbContext
{
public virtual DbSet<Student> students { get; set; }
public MyDatabaseContext() : base("MyDatabaseContextConnectionString")
{
System.Data.Entity.Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyDatabaseContext, Migrations.Configuration>());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// here we want to define the entities structure
}
}
You will find some more information about the initializer itself here (MSDN
- MigrateDatabaseToLatestVersion) and here (Entity Framework Tutorial - Code-First Tutorials - Automated Migration) is another example with some more background information and examples.
The answer of this question is to use T4 templates. After searching the web I got the answer that nobody could on SO. Shame...
https://archive.codeplex.com/?p=t4dacfx2tsql
I am trying to run the code first migration in entity framework 6.0. I have added 4 new entities in my entities modal. However when i run the "add-migration" command in VS 2013, the generated migration file contains the script of all entitles (just like the initial migration) in my modal, though they are already in linked database. Obviously when I rum "Update-Database" commends, it generates entity already exists error. My DBContext class looks like following:
public class BidstructDbContext : DbContext
{
public BidstructDbContext() : base(nameOrConnectionString: "Bidstruct")
{
this.Configuration.LazyLoadingEnabled = false;
}
public DbSet<User> Users { get; set; }
public DbSet<Role> Roles { get; set; }
public DbSet<Permission> Permissions { get; set; }
public DbSet<Company> Company { get; set; }
// New Added Table
public DbSet<Gadgets> Gadgets { get; set; }
public DbSet<Language> Language { get; set; }
public DbSet<LanguageKeys> TranslationKeys { get; set; }
public DbSet<Translations> Translations { get; set; }
static BidstructDbContext()
{
Database.SetInitializer(new DatabaseInitializer());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
}
}
and DatabaseInitializer class looks like as following:
public class DatabaseInitializer :
// CreateDatabaseIfNotExists<BidstructDbContext> // when model is stable
DropCreateDatabaseIfModelChanges<BidstructDbContext> // when iterating
{
private const int AttendeeCount = 1000;
// EF is NOT a good way to add a lot of new records.
// Never has been really. Not built for that.
// People should (and do) switch to ADO and bulk insert for that kind of thing
// It's really for interactive apps with humans driving data creation, not machines
private const int AttendeesWithFavoritesCount = 4;
protected override void Seed(BidstructDbContext context)
{
}
}
Any idea, how to resolve this problem. Its was working fine for me few days back but now I am facing this problem :(
Check to see if your context keys have changed, in your migration history.
I'm working on a project that has been using automatic migrations, but the automatic migration was not occurring due to a lot of class changes. In trying to switch to non-automatic migration, Add-Migration was regenerating the entire schema.
So I tried putting the manual table changes into the Up() of the DbMigration, and this applied a migration and an entry into the __MigrationHistory table, but with a different context key (the namespace and class name of my configuration file.)
A quick test of renaming the previous (older) migration record's context key to be the same as the current one caused the migration up/down to generate correctly.
Even then...it may not be 100%. Most of my changes were correct, but it started out adding a table which already existed, then turned around and removed it.