EF5 Code First - Changing A Column Type With Migrations
The smartest way is probably to not alter types. If you need to do this, I'd suggest you to do the following steps:
- Add a new column with your new type
- Use
Sql()
to take over the data from the original column using an update statement - Remove the old column
- Rename the new column
This can all be done in the same migration, the correct SQL script will be created. You can skip step 2 if you want your data to be discarded. If you want to take it over, add the appropriate statement (can also contain a switch statement).
Unfortunately Code First Migrations do not provide easier ways to accomplish this.
Here is the example code:
AddColumn("dbo.People", "LocationTmp", c => c.Int(nullable: false));
Sql(@"
UPDATE dbp.People
SET LocationTmp =
CASE Location
WHEN 'London' THEN 1
WHEN 'Edinburgh' THEN 2
WHEN 'Cardiff' THEN 3
ELSE 0
END
");
DropColumn("dbo.People", "Location");
RenameColumn("dbo.People", "LocationTmp", "Location");
How to change the column type in table using Entity Framework core
You should use EF Core migrations to update your db schema. The documentation is pretty good, so make sure to go through it.
However, this is a summary of how the process would be:
- Make the change in your model (which by convention will be automatically detected. Alternatively, use the Fluent API in your DB Context
OnCreate
method or in yourEntityConfiguration
s). - Add a migration running the following CLI command :
dotnet ef migrations add SomeDescriptiveNameAboutWhatThisMigrationWillDo
. - A migration file with an
Up
andDown
method will be automatically generated. TheUp
will be run when you apply the migration, and theDown
if you ever decide to revert it . You could add changes to the automatically scaffolded migration file. Based on the code in the migration file, EF Core will then generate a SQL script and apply the changes to the DB. - Once you have added (and maybe edited) the migration file, you need to apply it to the DB. You do that by running
dotnet ef migrations update
. - EF Core tracks all applied migrations in a table in your DB called by default
__EFMigrationsHistory
In your particular case of changing a column type, EF Core might try to drop the column and recreate it, which will result in data loss. If you wanna keep your data, I would recommend altering the migration script to actually split the process in two: first add a new column with the new type and a slightly different name, then write some custom SQL to migrate data from the old column to the new one, then delete the old column and finally rename the new column to the correct name. To be honest, I am not sure if there is some custom migration operation that will out of the box change the data type without data loss, there might be.
To double check if the migration will generate data loss or check if it will do what you expect it to do, you can generate the SQL script that will be used by running dotnet ef migrations script <from migration> <to migration>
. After reviewing it, you can either copy/paste and run the script in your DB, or just run the command detailed in step 4 above.
EF changing data type from string to int, how to drop and add column during migrations
Dropping the column and then re-creating it does not clear out the data in the table. Your Subscriptions
table will still have rows. Thus when you try to add the column which you declare as non-nullable with no default value you get the error (SQL cannot populate the current rows with non-null values without a default). The ALTER TABLE
statement is referenced because that is the SQL for adding a column:
ALTER TABLE Subscription ADD PlanType int not null
See docs
You will either need to declare a default or create it as non-nullable, populate it as part of the migration and then change it to non-nullable.
Rename a column and also changing the column type through migration in EF Code First
You can either reverse the migration, edit the C# entities and create a new migration. Use:
`Update-database -TargetMigration:0`
to revert all migrations, or,
`Update-database -TargetMigration:"name of migration file"`
to revert to a specific migration. Delete the unwanted migration file.
Then run Add-migration migration-name
having changed you code to create the new migration file.
The third option is to rename the fields in code then use `Add-migration'.
Avoid editing the migration file. Change the code, run a migration, update the database.
See also
EF migration for changing data type of columns
You have a default constraint on your column. You need to first drop the constraint, then alter your column.
public override void Up()
{
Sql("ALTER TABLE dbo.Received DROP CONSTRAINT DF_Receiv_FromN__25869641");
AlterColumn("dbo.Received", "FromNo", c => c.String());
AlterColumn("dbo.Received", "ToNo", c => c.String());
AlterColumn("dbo.Received", "TicketNo", c => c.String());
}
You will probably have to drop the default constraints on your other columns as well.
I've just seen Andrey's comment (I know - very late) and he is correct. So a more robust approach would be to use something like:
DECLARE @con nvarchar(128)
SELECT @con = name
FROM sys.default_constraints
WHERE parent_object_id = object_id('dbo.Received')
AND col_name(parent_object_id, parent_column_id) = 'FromNo';
IF @con IS NOT NULL
EXECUTE('ALTER TABLE [dbo].[Received] DROP CONSTRAINT ' + @con)
I know this probably doesn't help the OP but hopefully it helps anyone else that comes across this issue.
Changing column default values in EF5 Code First
Removal of default constraints inspired by reverse migrations produced by Entity Framework for SQL Server
public static void DropDefaultConstraint(string tableName, string columnName, Action<string> executeSQL)
{
string constraintVariableName = string.Format("@constraint_{0}", Guid.NewGuid().ToString("N"));
string sql = string.Format(@"
DECLARE {0} nvarchar(128)
SELECT {0} = name
FROM sys.default_constraints
WHERE parent_object_id = object_id(N'{1}')
AND col_name(parent_object_id, parent_column_id) = '{2}';
IF {0} IS NOT NULL
EXECUTE('ALTER TABLE {1} DROP CONSTRAINT ' + {0})",
constraintVariableName,
tableName,
columnName);
executeSQL(sql);
}
It's slightly shorter, but the usage is the same.
DropDefaultConstraint(TableName, "DefaultTaxPerDollar", q => Sql(q));
The Guid is used to make a unique variable name in case you are going to drop several constraints in one migration.
Related Topics
How Set Value a Property Selector Expression<Func<T,Tresult>>
How Are Dlls Loaded by the Clr
Why Must C# Operator Overloads Be Static
Dotnet.Highcharts: Cost Not Plotted Against the Correct Date
How to Convert a String to Ascii to Binary in C#
How to Convert Image to Data Uri for HTML with C#
How to Get Max Value of a Column Using Entity Framework
Soap Authentication Fails When Running a C# App on a Linux Box
How Does Garbage Collection and Scoping Work in C#
C# Linq to SQL: Refactoring This Generic Getbyid Method
What Uri Protocols Exist on Windows Phone 8
How to Call a .Net Assembly from C/C++
Multiple SQL Statements in One Roundtrip Using Dapper.Net
Print HTML Document from Windows Service in C# Without Print Dialog