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

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.

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 .

FluentMigrator - how does it know which migration to execute

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.

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.

Entity Framework Code First - T-SQL Views

I'm creating a SQL View on my Configuration Seed
protected override void Seed(QuiverContext context)
{
context.Database.ExecuteSqlCommand(DatabaseScripts.Views.MyView);
}
Now I want to add a DBSet to my DbContext that represents my View. I read that one can do this using then the Entity like a regular table.
So I tried but it requires me to add a migration which I did, but then the update-database command fails when creating the view since a table is created first.
It looks like you're trying to create a view in your Seed method. This isn't the way to create a view (remember the seed method runs every time ANY migration runs).
The better way to be would be to add a migration. This will create a code file containing CreateTable lines, which will make your table. Just remove these lines, and replace them with a call to create your view.
You can execute custom Sql inside a migration using the Sql command, for example...
Sql("CREATE VIEW myView.....");
If you want to make things a bit more robust, you can create an extension for migrations which allows you to call CreateView.

Categories