Trying to alter a column from a text field to a jsonb field using Entity Framework code-first migrations.
The column mostly has json objects stored as text but some are not valid json. When trying to run the migration it throws the error:
Exception: 42804: column "Message" cannot be cast automatically to type jsonb
Code:
migrationBuilder.AlterColumn<string>(
name: "Message",
schema: "database",
table: "ScheduledEvent",
type: "jsonb",
nullable: false,
oldClrType: typeof(string),
oldType: "text");
In this thread, https://github.com/npgsql/efcore.pg/issues/144, they have the same issue and say the solution was to add a USING clause.
How can I update the code first EF model to add a USING clause in the migration?
I am working in a company where a project has been brought in house because the external team tasks with building the system have not done a great job and thus been fired.
An issue that I have is that we have an existing database, where some tables where seed data should have been done through a migrationBuilder looks to have just been inserted via SSMS \ SQL Server Insert scripts.
as a result I get an error like this when adding seeding scripts so that when we spin up an new isntance of the database this works, but on an existing environment such as dev, test and staging it does not.
Violation of PRIMARY KEY constraint 'PK_xxxx'. Cannot insert duplicate key in object 'forms.AnswerTypes'. The duplicate key value is (1)
The only potential way I have found around this is from this link here
https://entityframeworkcore.com/knowledge-base/54553668/add-or-update-data-to-existing-database-with-entity-framework
But hope that there are better ways that this can be acheived as I cannot delete the data as part of the migration because its already used and being referenced by other tables so the ripple effect is wide ranging.
An example of the sort of data that I am trying to seed is like this;
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.InsertData(
schema: "forms",
table: "Rules",
columns: new[] { "RuleId", "Rules" },
values: new object[] { 1, "Any" });
migrationBuilder.InsertData(
schema: "forms",
table: "Rules",
columns: new[] { "RuleId", "Rules" },
values: new object[] { 2, "All" });
}
So, the question is, is it possible with migrationBuilder to check is data exists prior to inserting?
You can write custom SQL and stuff and add it to your migration script;
https://learn.microsoft.com/en-us/ef/core/managing-schemas/migrations/operations
There's also .Sql():
https://learn.microsoft.com/en-us/ef/core/managing-schemas/migrations/?tabs=dotnet-core-cli#customize-migration-code
migrationBuilder.Sql(
#"
UPDATE Customer
SET Name = FirstName + ' ' + LastName;
");
Which you could use. My team and i use EF6 still but we use the same principle. Our migrationscript sometimes have additional SQL statements to move any data around or generate default data when adding a column etc.
This is short: I have mistakenly set a property string when it should've been int. There are no constraints as this int may be optional. Even though I could make the int nullable, I rather have it a default value of zero.
Then when I try to run migrations:
Cannot insert the value NULL into column 'Edad', table
'EduPlaTools.dbo.Profesor'; column does not allow nulls. UPDATE fails.
The statement has been terminated.
Which makes sense. What it's doing is updating the fields, and since many fields had "NULL", it's getting inserted. Is there a way to map those NULLs into zeroes automatically? Or do I need to do an SQL Statement?
Here's the migrationBuilder code:
migrationBuilder.AlterColumn<int>(
name: "Edad",
table: "Profesor",
nullable: false,
oldClrType: typeof(string),
oldNullable: true);
If you are trying to change the type of a column and there are already existing records in your table, those records need to have some value specified for each of the new columns. If you have not specified a default value for the column, the database will attempt to use NULL, which will fail because the column does not allow nulls.
Oh no. I need to apologize. So dumb for not realizing this, Entity Framework apparently scaffolded other table with a similar property Profesor, when in fact it was Estudiante that needed change.
migrationBuilder.AlterColumn<int>(
name: "Edad",
table: "Estudiante",
nullable: false,
oldClrType: typeof(string),
oldNullable: true,
defaultValue: 0);
Now everything is working! Thanks everybody!
I am trying to do this:
ALTER TABLE CompanyTransactions DROP COLUMN Created
But I get this:
Msg 5074, Level 16, State 1, Line 2
The object 'DF__CompanyTr__Creat__0CDAE408' is dependent on column 'Created'.
Msg 4922, Level 16, State 9, Line 2
ALTER TABLE DROP COLUMN Created failed because one or more objects access this column.
This is a code first table. Somehow the migrations have become all messed up and I am trying to manually roll back some changed.
I have no idea what this is:
DF__CompanyTr__Creat__0CDAE408
You must remove the constraints from the column before removing the column. The name you are referencing is a default constraint.
e.g.
alter table CompanyTransactions drop constraint [df__CompanyTr__Creat__0cdae408];
alter table CompanyTransactions drop column [Created];
The #SqlZim's answer is correct but just to explain why this possibly have happened. I've had similar issue and this was caused by very innocent thing: adding default value to a column
ALTER TABLE MySchema.MyTable ADD
MyColumn int DEFAULT NULL;
But in the realm of MS SQL Server a default value on a colum is a CONSTRAINT. And like every constraint it has an identifier. And you cannot drop a column if it is used in a CONSTRAINT.
So what you can actually do avoid this kind of problems is always give your default constraints a explicit name, for example:
ALTER TABLE MySchema.MyTable ADD
MyColumn int NULL,
CONSTRAINT DF_MyTable_MyColumn DEFAULT NULL FOR MyColumn;
You'll still have to drop the constraint before dropping the column, but you will at least know its name up front.
As already written in answers you need to drop constraints (created automatically by sql) related to all columns that you are trying to delete.
Perform followings steps to do the needful.
Get Name of all Constraints using sp_helpconstraint which is a system stored procedure utility - execute following exec sp_helpconstraint '<your table name>'
Once you get the name of the constraint then copy that constraint name and execute next statement i.e alter table <your_table_name>
drop constraint <constraint_name_that_you_copied_in_1> (It'll be something like this only or similar format)
Once you delete the constraint then you can delete 1 or more columns by using conventional method i.e Alter table <YourTableName> Drop column column1, column2 etc
When you alter column datatype you need to change constraint key for every database
alter table CompanyTransactions drop constraint [df__CompanyTr__Creat__0cdae408];
You need to do a few things:
You first need to check if the constrain exits in the information schema
then you need to query by joining the sys.default_constraints and sys.columns
if the columns and default_constraints have the same object ids
When you join in step 2, you would get the constraint name from default_constraints. You drop that constraint. Here is an example of one such drops I did.
-- 1. Remove constraint and drop column
IF EXISTS(SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = N'TABLE_NAME'
AND COLUMN_NAME = N'LOWER_LIMIT')
BEGIN
DECLARE #sql NVARCHAR(MAX)
WHILE 1=1
BEGIN
SELECT TOP 1 #sql = N'alter table [TABLE_NAME] drop constraint ['+dc.name+N']'
FROM sys.default_constraints dc
JOIN sys.columns c
ON c.default_object_id = dc.object_id
WHERE dc.parent_object_id = OBJECT_ID('[TABLE_NAME]') AND c.name = N'LOWER_LIMIT'
IF ##ROWCOUNT = 0
BEGIN
PRINT 'DELETED Constraint on column LOWER_LIMIT'
BREAK
END
EXEC (#sql)
END;
ALTER TABLE TABLE_NAME DROP COLUMN LOWER_LIMIT;
PRINT 'DELETED column LOWER_LIMIT'
END
ELSE
PRINT 'Column LOWER_LIMIT does not exist'
GO
In addition to accepted answer, if you're using Entity Migrations for updating database, you should add this line at the beggining of the Up() function in your migration file:
Sql("alter table dbo.CompanyTransactions drop constraint [df__CompanyTr__Creat__0cdae408];");
You can find the constraint name in the error at nuget packet manager console which starts with FK_dbo.
I had the same problem and this was the script that worked for me with a table with a two part name separated by a period ".".
USE [DATABASENAME]
GO
ALTER TABLE [TableNamePart1].[TableNamePart2] DROP CONSTRAINT [DF__ TableNamePart1D__ColumnName__5AEE82B9]
GO
ALTER TABLE [TableNamePart1].[ TableNamePart1] DROP COLUMN [ColumnName]
GO
I needed to replace an INT primary key with a Guid. After a few failed attempts, the EF code below worked for me. If you hyst set the defaultValue... you end up with a single Guid a the key for existing records.
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropUniqueConstraint("PK_Payments", "Payments");
migrationBuilder.DropColumn(
name: "PaymentId",
table: "Payments");
migrationBuilder.AddColumn<Guid>(
name: "PaymentId",
table: "Payments",
type: "uniqueidentifier",
defaultValueSql: "NewId()",
nullable: false);
}
Copy the default constraint name from the error message and type it in the same way as the column you want to delete.
I had the same problem, I could not remove migrations, it would show error that something is already applied, so i changed my DB name in appsettings, removed all migrations, and then added new migration and it worked. Dont understand issue completely, but it worked
I fixed by Adding Dropping constraint inside migration.
migrationBuilder.DropForeignKey(
name: "FK_XX",
table: "TableX").
and below recreates constraint.
migrationBuilder.AddForeignKey(
name: "FK_XX",
table: "TableX",
column: "ColumnX",
onDelete: ReferentialAction.Restrict);
In EF4 is it possible to have a referential contstraint which is based upon just a substring of a value?
e.g.
Ref table:
Code: varchar(5)
Desc: varchar(50)
Main Table:
Code: varchar(6)
Data1:
Data2: etc...
I would like to have a constraint where MainTable.Code.Substring(0,5) > RefTable.Code
Is that possible?
No this is not possible and I doubt that you can create such relation in database - EF follows same rules as relational database.
Edit: Actually there can be a way to achieve that if you try to represent it as a query inside QueryView.