FluentMigrator - how does it know which migration to execute - c#

How does FluentMigrator know what migrations to execute / migrate when you start up the application?
Example: I got two migrations already performed (1 and 2). Now I create a third migration and give it an id of 3. When I launch my application, FluentMigrator will execute the migrations, but how does it know to skip the first two?
using FluentMigrator;
namespace test
{
[Migration(3)]
public class AddLogTable : Migration
{
public override void Up()
{
Create.Table("Log")
.WithColumn("Id").AsInt64().PrimaryKey().Identity()
.WithColumn("Text").AsString();
}
public override void Down()
{
Delete.Table("Log");
}
}
}

It stores all information in “VersionInfo” table by default. Using this information, it can determine what migrations need to be applied to that database and will then execute each migration in succession that it needs to apply. Also, you can manage metadata of this table if you need

A table called VersionInfo is created in the database where information about each migration is recorded. Before applying the migration, a check will be performed to see what records are already in this table.

Related

How can I run SQL script in OnModelCreating by EF Core?

My program has an existing SQLite database.
In the new version of the program, it needs to add a column for a feature.
Now the program is made by .NET 6 (WPF) and EF Core 6.
I have to detect whether the new column existed and add it or not.
Here is my code in OnModelCreating to detect the column existed or not:
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
var Result = Database.ExecuteSqlRaw("SELECT Count(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='BindDesign' AND COLUMN_NAME='type'");
}
After the code run, it reports this error:
An attempt was made to use the model while it was being created. A DbContext instance cannot be used inside 'OnModelCreating' in any way that makes use of the model that is being created
How can I solve this? Thank you.
You should use migrations to add columns in the database.
If you want to apply migrations on startup you can check if the database needs to be migrated and apply the migration with something like this
if (_context.Database.GetPendingMigrations().Any()) {
await _context.Database.MigrateAsync();
}
Try to Use Different Context for your schema , the error message is clear , you can on use makes use of the model that is being created.
just make another context for your schema .

MVC 5 EF - Error when trying to change Table name

I have a class named "Ciudad". When I want to add a migration to create the datatable, EF uses the name "dbo.Ciudads". I actually wanted the name to be "Ciudades" (with an additional 'e') so I changed it manually.
After updating the databse the table dbo.Ciudades was created successfully. I even created a small script to populate it and it run ok.
However, when I want to query "Ciudades" from the context, I get an exception because it tries to query the table "dbo.Ciudads" (without the additional 'e') which doesn't actually exists. It is an InvalidOperationException: "The model backing the 'ApplicationDbContext' context has changed since the database was created"
So I ran "add-migration foo" and it generates the following migration:
public partial class foo : DbMigration
{
public override void Up()
{
RenameTable(name: "dbo.Ciudads", newName: "Ciudades");
}
public override void Down()
{
RenameTable(name: "dbo.Ciudades", newName: "Ciudads");
}
}
It seems strange because in my database I DO have the table exactly as I wanted with the name "Ciudades". Nevertheless, when I try to update the database with this migration, I get the following exception:
System.Data.SqlClient.SqlException (0x80131904): Either the parameter #objname is ambiguous or the claimed #objtype (OBJECT) is wrong.
I imagine I get this exception because the table "Ciudads" doesn't exist. Am I correct?
If so, where it is getting that table from? I did a search on the Entire Solution for the word "ciudads" and nothing came up.
Thanks to #IvanStoev for the solution.
The problem was that I manually changed the table name in the generated migration class. Later I used FluentAPI to specify the name "Ciudades" but it was to late.
As per #IvanStoev suggestion I deleted everything and created the migrations again, but this time using FluentAPI BEFORE creating the migrations. The table was then generated with the name I intended and everything is working fine now.
You can use this approach .
public override void Up()
{
RenameTable("dbo.Ciudads", "Ciudades");
}
public override void Down()
{
RenameTable("dbo.Ciudades", "Ciudads");
}
Or
If you want to specify your table name.You can use fluent API.
modelBuilder.Entity<Department>().ToTable("t_Department");
It's probably worth downloading microsoft SQL server management studio dev edition.

Entity framework code first migration coming up blank

I am using entity framework to attach to an existing database where I will add a few more tables. Someone on here said this is not possible and I would need to keep the new tables separate in a new database. Here is that question:
Do not create existing table during Migration
I did some more investigation and found this on MSDN:
https://msdn.microsoft.com/en-us/data/dn579398.aspx
According to this I should run an initial migration like this:
add-migration initial -ignorechanges
so I did that and that is supposed to look at the database and match it up. After I update the database, then I am supposed to add another migration without the -ignorechanges. When I do the second migration, I get this:
namespace PTEManager.Domain.Migrations
{
using System;
using System.Data.Entity.Migrations;
public partial class second : DbMigration
{
public override void Up()
{
}
public override void Down()
{
}
}
}
so it is not trying to add the 2 new tables and relationships that I need. It is coming up blank. I have tried deleting the _migrationhistory table from the database and starting over but still nothing. What am I missing?
It sounds like you are adding the second migration without making any changes. What you need to do is this:
Add DBSet<ModelName> properties to your context for all existing
tables.
Create the initial migration using -ignorechanges
Add DBSet<ModelName> properties to your context for all new tables.
Create the second migration as normal.
The second migration should then contain code to create only the new tables, relationships etc. you want. It doesn't matter whether you update the database in between migrations or only once at the end.
You could try to add normal migration and modify Up/Down methods so they include only the 2 new tables.

Create table and insert data into it during EF code first migration

I'm using Entity Framework Code First with Code First migrations.
During a migration, I need to create a new table, and then insert some data into it.
So I create the table with :
CreateTable("MySchema.MyNewTable",
c => new
{
MYCOLUMNID = c.Int(nullable: false, identity: true),
MYCOLUMNNAME = c.String(),
})
.PrimaryKey(t => t.MYCOLUMNID);
Then I try to insert data with :
using (var context = new MyContext())
{
context.MyNewTableDbSet.AddOrUpdate(new[]
{
new MyNewTable
{
MYCOLUMNNAME = "Test"
}
});
context.SaveChanges();
}
But I get an error :
Invalid object name 'mySchema.MyNewTable'.
Is it possible to do what I need ? Create a table and inserto data into it in the same migration ?
I already have other migrations where I create tables or insert data into a table, but never in the same migration...
My recommendation is move that insert code to the Seed method. Migrations introduced its own Seed method on the DbMigrationsConfiguration class. This Seed method is different from the database initializer Seed method in two important ways:
It runs whenever the Update-Database PowerShell command is executed.
Unless the Migrations initializer is being used the Migrations Seed
method will not be executed when your application starts.
It must handle cases where the database already contains data because
Migrations is evolving the database rather than dropping and
recreating it.
For that last reason it is useful to use the AddOrUpdate extension method in the Seed method. AddOrUpdate can check whether or not an entity already exists in the database and then either insert a new entity if it doesn’t already exist or update the existing entity if it does exist.
So, try to run the script that you want this way:
Update-Database –TargetMigration: ScriptName
And the Seed method will do the job of inserting data.
As Julie Lerman said on her blog:
The job of AddOrUpdate is to ensure that you don’t create duplicates
when you seed data during development.
You can try this approach:
after creating table,
create another empty migration in your Package Manager Console using:
Add-Migration "MigrationName"
Then open the .cs file of that migration and, in Up() method, insert this code:
Sql("INSERT INTO MyNewTable(NyColumnName) Values('Test')");
After that, save and go back to Package Manager Console and update the database using:
Update-Database
A way to do "random" things in migrations is to use the Sql method and pass whatever SQL statement you need to perform, for example, inserting data.
This is the best approach if you want your migrations to be able to generate a complete migration SQL script, including your data operations (the Seed method can only be executed in code and won't generate any sql script).
For those who looking for EF Core solution, In the Up method, and after creating the table:
i.e: migrationBuilder.CreateTable(name: "MyTable", .....
add the following code:
migrationBuilder.InsertData(table: "MyTable", column: "MyColumn", value: "MyValue");
or
migrationBuilder.InsertData(table: "MyTable", columns: ..., values: ...);
For more information see the docs: MigrationBuilder.InsertData Method
First I run the
PM> Add-Migration MyTableInsertInto
then I got following,
**The Designer Code for this migration file includes a snapshot of your current Code First model. This snapshot is used to calculate the changes to your model when you scaffold the next migration. If you make additional changes to your model that you want to include in this migration, then you can re-scaffold it by running 'Add-Migration MyTableInsertInto' again.
**
I have used following code for c# data migrations
public partial class MyTableInsertInto : DbMigration
{
public override void Up()
{
Sql("INSERT INTO MyNewTable(MyColumnName) Values ('Test')");
}
public override void Down()
{
Sql("DELETE MyNewTable WHERE MyColumnName= 'Test'");
}
}
Then I run following
PM> update-database
Specify the '-Verbose' flag to view the SQL statements being applied to the target database.
Applying explicit migrations: [202204120936266_MyNewTableInsertInto].
Applying explicit migration: 202204120936266_MyNewTableInsertInto.
Running Seed method.
After running the seed method data base is updated successfully and this works fine for me.

EF migration shows empty Up() Down() methods

I have a local database that is currently in it's second version and should now go to it's third version.
The code for the previous migrations was generated by another programmer so I am assuming I am doing something wrong here.
In my model there are around 30 classes, and inside the model folder there is a mapping folder and it contains the mappings for those 30 classes.
So now I added 1 new class in the same manner as those previous classes and then run the add-migration command in the Package Manager Console.
Infortunately I get an empty migration Up() and Down() method.
When I look in the database there is a __migrationHistory available with the previous 2 migrations. If I run my application now, the third migration is also added but obviously the new table is not being created because it's not in the Up() method.
What could I be doing wrong?
I think something is going wrong when scaffolding the previous migrations... It's like it can't find the new Code-First classes I have added.
This is my command:
add-migration "1.2" -verbose -ProjectName "MyEFproject"
I am assuming that the scaffolding doesn't know where to look for the new class... or is this by convention that all model classes are just expected to be in the project?
Result of add-migration:
namespace MyProject.Migrations
{
using System;
using System.Data.Entity.Migrations;
public partial class _1002 : DbMigration
{
public override void Up()
{
}
public override void Down()
{
}
}
}
Sample of new Model Class:
using System;
using System.Collections.Generic;
namespace MyProject.Models
{
public partial class MyTable
{
public string SomeId { get; set; }
public string SomeText { get; set; }
}
}
Sample of new Mapping class
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;
namespace MyProject.Models.Mapping
{
public class MyTableMap : EntityTypeConfiguration<MyTable>
{
public MyTableMap()
{
// Primary Key
this.HasKey(t => t.SomeId);
// Properties
this.Property(t => t.SomeText)
.IsRequired()
.HasMaxLength(30);
// Table & Column Mappings
this.ToTable("MyTable", "database");
this.Property(t => t.SomeId).HasColumnName("SomeId");
this.Property(t => t.SomeText).HasColumnName("SomeText");
}
}
}
Thank you,
You need to add your table to your implementation of the DbContext class, e.g.
public class MyDatabaseEntities : DbContext {
public virtual DbSet<MyTable> MyTable { get; set; }
}
While rolling back an existing EF Core Data Context back to empty, my migrations wouldn't generate until I removed the ApplicationDbContextModelSnapshot that accompanied the migrations.
This class is auto-generated and needs to align with your current migration level.
I was able to fix this issue by deleting a record of last migration from _MigrationHistory table.
This record had been incorrectly created before I added DbSet for new model object to DbContext class.
After this deletion new migration was created with correct Up() and Down() methods.
I had this problem because I forgot to add {get; set;} after my variable names
You need to add your table to your implementation of the DbContext class, e.g. While rolling back an existing EF Core Data Context back to empty, my migrations wouldn't generate until I REMOVED the ApplicationDbContextModelSnapshot that accompanied the migrations.
In my case, the datacontext project is a class lib project. It is different from the startup project which is asp.net mvc 5 project. Now by mistake the connection string in the startup project is pointing to a different database.
So ensure that datacontext project and startup project point to the same database. Also use the full command as mentioned in the question like the following. You can include -Force as well.
add-migration "InitialMigration" -verbose -ProjectName "MyEFproject" -Force
Also: Make sure any new properties you've added are public!
In my case I was doing a migration where I added fields to an existing table and was ending up with empty Up and Down methods,
I had something like this:
public bool ExistingField { get; set; }
bool NewField { get;set; }
Can you spot the difference...?
If you make this mistake rerun the migration with the same name (you probably will need to add the -Force parameter to scaffold it full).
PS. Always make sure your project builds fully before attempting to do any kind of EF command. If your project doesn't already build you're asking for trouble.
You need to add your MyTable in Dbset and your issue will be resolved:
public DbSet<MyTable> MyTables { get; set; }
I was getting empty migrations added when I had mistakenly related two tables using a 1-many relationship rather than a many-many (i.e. i forgot one of the navigation properties). I had a seeding file that was expecting a many-many relationship and was subsequently failing during the migration causing the migration to fail. Unfortunately there was no output that made it obvious that was the problem and it was only by using the Entity Framework Power Tools (v4 but installed in VS2015) did i visually see the incorrect relationship and realize it was probably the cause.
I had to Update-Database with the latest migration before the empty one appending this parameter -TargetMigration:"{your-migration-name}".
Probably it will tell you that there will be data loss from the next buggy one we tried. If you can afford it append -Force to it.
Then I tried to add my new Add-Migration and it wasn't empty.
Final thing that you may need to do if above is throwing exception is to go SQL Server Management Studio and delete the last Automatic migration and try to add it again.
if new tables added to Context
just remove new table in "Migration/ExampleContextModelSnapshot"
I had the same issue on EFcore. When renaming Phone -> mobile, the migration came up empty.
My DbContext :
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<MyUser>()
.Property(c => c.Mobile)
.HasColumnName("phone");
}
Problem was using .HasColumnName("phone") was overriding the actual property name so EF probably couldn't see any change.
Changing string value made it work.
I had this exact issue after I wanted to add an extra column to my database. Because my data would not seed unless the tables were empty, I deleted all the tables and the migrations to recreate the tables. When I tried to migrate, the migration had empty up and down methods.
I solved this by deleting the snapshot file as this was creating the issue. So I deleted all the migrations and the snapshot file, added the migration again and ran update database. The tables and migrations were successfully updated with my new column.
A better way to do this though is to run the down method and drop the tables like that if you are working on test data. Obviously this is bad in the real world to drop tables.
To me the problem was that Id property that should correspond to table id was named FeedbackId.
I changed to "Id" and then Up/Down weren't empty anymore.
Dunno if that can help somehow
If your project is small, i.e. you do not have too many migrations yet, you can delete all from your Migration folder. After that, add the migrations again.
I think this also happens when u try to do migration without any changes in the models. eg when you do migration one and succeed, when u try to do migration2 without doing any changes in any of the models, it will create empty UP and Down.
From the perspective of a complete Entity Framework (Core) beginner:
Create your class which will become your table
You can have subclasses with many-to-many or one-to-one relationships.
In step 3 you see the context where both properties have a one-to-one relationship.
Ensure you have one DbContext
If you have more than one DbContext you need to specify which context you want to add the migration to with the -Context parameter.
Add your class to your DbContext as shown by #CondingIntrigue
As a reference The Entity Framework Core DbSet
public class AccountContext : DbContext
{
public DbSet<Account> Accounts { get; set; }
public DbSet<SecretIdentity> SecretIdentity { get; set; }
}
Enter Add-Migration
In my case, I was encountering similar problems with Visual Studio Code.
I have fixed these by doing the following:
Check inside your ContextModelSnapshot : ModelSnapshot
Comment Model Entity Definition…
Delete your migration files related to these entity
Delete the migrations from the dbo.__EFMigrationsHistory table
Compile your solution.
Run the following commands:
dotnet ef migrations add migrationName -p ProjectContainer/
dotnet watch run
Temprorary remove
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
}
and then do initial create
Add-Migration InitialCreate
If after adding your class in the dbContext and your migration is still empty: do the following:
In your DbContextModelSnapshot class, remove every related code to that class name that you are trying to apply add-migration on. Save the DbContextModelSnapshot.cs and use the Add-Migration "Added_filename"
This work for me.
In my case ,I deleted Migration folder completely. As long as I didn't remove the "ApplicationDbContextModelSnapshot" and all previous migrationas it didn't work.
For me it was because I hadn't add Configuration files.
onModelCreating:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfigurationsFromAssembly(typeof(AppDbContext).Assembly);
}
and add configurations in same assembly derived from IEntityTypeConfiguration<T> where T is your model.
I missed adding
{get;set}
After adding getter and setter, up and down methods are not empty.

Categories