EF Core migration taking old migrations changes along with new columns - entity-framework

I have added 2 more columns in aspnetusers table and added migrations. But it's failing and showing error stating FK_Projects_AspNetUsers_UserId' is not a constraint.
Could not drop constraint. See previous errors.
public string NavbarBackGroundImagePath { get; set; }
public string NavbarBackGroundColorCode { get; set; }
Added these 2 columns.
migrationBuilder.DropForeignKey(
name: "FK_Projects_AspNetUsers_UserId",
table: "Projects");
migrationBuilder.DropIndex(
name: "IX_Projects_UserId",
table: "Projects");
migrationBuilder.DropColumn(
name: "UserId",
table: "Projects");
migrationBuilder.AddColumn<int>(
name: "WorkspaceId",
table: "Projects",
nullable: false,
defaultValue: 0);
migrationBuilder.AddColumn<string>(
name: "NavbarBackGroundColorCode",
table: "AspNetUsers",
maxLength: 10,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "NavbarBackGroundImagePath",
table: "AspNetUsers",
maxLength: 200,
nullable: true);
migrationBuilder.CreateIndex(
name: "IX_Projects_WorkspaceId",
table: "Projects",
column: "WorkspaceId");
migrationBuilder.AddForeignKey(
name: "FK_Projects_Workspaces_WorkspaceId",
table: "Projects",
column: "WorkspaceId",
principalTable: "Workspaces",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
But in migration file it's taking all these things.

According to the error message, it seems that this error happens when you want to drop the foreign key constraint in the Projects table, if the Projects table doesn't contain the "FK_Projects_AspNetUsers_UserId" constraint or doesn't contain the "UserId" property, it will show this error.
So, please check the Projects table in the database, whether you have removed the UerId column. And whether the Projects table have the foreign key constraint with the AspNetUsers table. If the Projects table doesn't contain this constraint, try to remove the DropForeignKey related code:
migrationBuilder.DropForeignKey(
name: "FK_Projects_AspNetUsers_UserId",
table: "Projects");

Related

How to set delete behavious for many to many in efcore 6

I have a webapi for climbing routes where there is a many to many relationship between Routes and Holds. 1 Hold can be in many Routes, and 1 Route can have many holds.
When I delete a route, the hold should not be deleted but the many to many relationship entry should be. When I delete a hold, same deal, the route should not be delete, but the relationship should be.
If I set up my classes and run a migration I get a migration file that contains the many to many table:
migrationBuilder.CreateTable(
name: "CRouteHold",
columns: table => new
{
HoldsId = table.Column<int>(type: "int", nullable: false),
RoutesId = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_CRouteHold", x => new { x.HoldsId, x.RoutesId });
table.ForeignKey(
name: "FK_CRouteHold_Holds_HoldsId",
column: x => x.HoldsId,
principalTable: "Holds",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_CRouteHold_Routes_RoutesId",
column: x => x.RoutesId,
principalTable: "Routes",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
This obviously doesn't work. I have to change the onDelete property of the second block - name: "FK_CRouteHold_Routes_RoutesId", - to NoAction. Then it seems to work. However, while I have to overwrite this in the migration file manually before I run update database... for some reason I can't get the migration to do this automatically.
I've tried variations of the following in my DBContext onmodelcreating method:
modelBuilder
.Entity<CRoute>()
.HasMany(e => e.Holds)
.WithMany(e => e.Routes)
.UsingEntity<Dictionary<string, object>>(
"CRouteHold",
b => b.HasOne<Hold>().WithMany().OnDelete(DeleteBehavior.Cascade),
b => b.HasOne<CRoute>().WithMany().OnDelete(DeleteBehavior.NoAction));
But it doesn't actually add the noAction to the migration file. It just gets rid of the onDelete property entirely, which then fails to have the expected outcome. I keep having to add it in manually. If I try anyt other delete behaviour, i.e. Restrict, it gets added to the migration file. It's just NoAction that doesn't seem to work.
If I get rid of both OnDelete settings from this onmodelcreating script, then the unit tests pass, but the update-database command fails due to cascade cycles.
Am I writing this correctly?
Better yet, is it possible to make the columns on the join table nullable?

EF Core 5 migrations - update composite primary and foreign keys

I am using EF Core code first migrations. I have two tables (models), TableA has 4 columns which are set as composite primary key and TableB has the same 4 columns set as primary key and foreign key to TableA.
On of the four columns is of type int and I need to change it to long. I changed the type to long in both models and added a new migration. However, I am getting the following error when trying to update the database to apply the migration:
The object 'PK_TableA' is dependent on column 'Number'.
The object 'FK_TableB_TableA_Column1_Column2_Column3_Column4' is dependent on column 'Number'.
ALTER TABLE ALTER COLUMN Number failed because one or more objects access this column.
The column Number (column #3) in the error above is the one which has the type of int.
The generated migration is as follows:
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<long>(
name: "Number",
table: "TableA",
type: "bigint",
nullable: false,
oldClrType: typeof(int),
oldType: "int");
migrationBuilder.AlterColumn<long>(
name: "Number",
table: "TableB",
type: "bigint",
nullable: false,
oldClrType: typeof(int),
oldType: "int");
}
I checked a number of topics here but none of them includes a solution for a "composite primary and foreign keys".
I found this article about manually changing the generated migration code. But I am not sure if it s going to work with a composite primary and foreign key. Or, if it is the right way to fix this issue.
Any advise will be appreciated.
Just in case someone was looking for an answer to this question, this is how I solved the issue.
I edited the generated migration code, as follows, to manually remove the foreign key first in TableB and then the two composite primary keys in TableA and TableB and then added them after changing the column type to bigint (according to the generated migration code):
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_TableB",
table: "TableB");
migrationBuilder.DropPrimaryKey(
name: "PK_TableA",
table: "TableA");
migrationBuilder.DropPrimaryKey(
name: "PK_TableB",
table: "TableB");
migrationBuilder.AlterColumn<long>(
name: "Number",
table: "TableA",
type: "bigint",
nullable: false,
oldClrType: typeof(int),
oldType: "int");
migrationBuilder.AlterColumn<long>(
name: "Number",
table: "TableB",
type: "bigint",
nullable: false,
oldClrType: typeof(int),
oldType: "int");
migrationBuilder.AddPrimaryKey(
name: "PK_TableA",
table: "TableA",
columns: new[] { "Column1", "Column2", "Column3", "Column4" });
migrationBuilder.AddPrimaryKey(
name: "PK_TableB",
table: "TableB",
columns: new[] { "Column1", "Column2", "Column3", "Column4" });
migrationBuilder.AddForeignKey(
name: "FK_TableB",
table: "TableB",
columns: new[] { "Column1", "Column2", "Column3", "Column4" },
principalTable: "TableA",
principalColumns: new[] { "Column1", "Column2", "Column3", "Column4" },
onDelete: ReferentialAction.Cascade);
}
The same code was added for the Down method.

Postgres - cannot use subquery in DEFAULT expression

A new unique column is being added to a table. This column's value comes from a C# random code generator method, but for existing rows I need to rely on Postgres.
I have the following EF Core migration:
protected override void Up(MigrationBuilder migrationBuilder)
{
var randomCodeSql = #"
SELECT string_agg (substr('ABCDEFGHJKLMNPQRSTUVWXYZ123456789', ceil (random() * 33)::integer, 1), '')
FROM generate_series(1, 6)";
migrationBuilder.AddColumn<string>(
name: "reference_code",
table: "invitations",
type: "character varying(12)",
maxLength: 12,
nullable: false,
defaultValueSql: randomCodeSql);
migrationBuilder.CreateIndex(
name: "ix_invitations_reference_code",
table: "invitations",
column: "reference_code",
unique: true);
}
The raw SQL is from this answer.
I get this error:
0A000: cannot use subquery in DEFAULT expression
Is there a code-first solution to this problem?

Entity framework code first migration not always working well

I have created a migration for my recent changes to my model that resulted in the following script,
DropIndex("dbo.InboundActions", new[] { "ReferredFrom_Id1" });
DropIndex("dbo.InboundCopyActionLogs", new[] { "InboundReferToEmployee_Id" });
DropIndex("dbo.InboundCopyActions", new[] { "ReferredFrom_Id1" });
DropColumn("dbo.InboundActions", "ReferredFrom_Id");
DropColumn("dbo.InboundCopyActions", "ReferredFrom_Id");
RenameColumn(table: "dbo.InboundCopyActionLogs", name: "InboundReferToDivision_Id", newName: "InboundRefer_Id");
RenameColumn(table: "dbo.InboundCopyActions", name: "ReferredFrom_Id1", newName: "ReferredFrom_Id");
RenameColumn(table: "dbo.InboundCopyActionLogs", name: "InboundReferToEmployee_Id", newName: "InboundRefer_Id");
RenameColumn(table: "dbo.InboundActions", name: "ReferredFrom_Id1", newName: "ReferredFrom_Id");
RenameIndex(table: "dbo.InboundCopyActionLogs", name: "IX_InboundReferToDivision_Id", newName: "IX_InboundRefer_Id");
Now when I try to update the database I get the following errors,
The index 'IX_ReferredFrom_Id' is dependent on column 'ReferredFrom_Id'.
The object 'FK_dbo.InboundActions_dbo.Divisions_ReferredFrom_Id' is dependent on column 'ReferredFrom_Id'.
ALTER TABLE DROP COLUMN ReferredFrom_Id failed because one or more objects access this column.
This is not the first time I find this kind of errors with migrations, which forces to me drop all migrations and database and start with brand new migrations which of course isn't practical, is there a problem with EF or me?!

How to avoid DROP DEFAULT statements with Doctrine 2 Migrations diff on first run?

I had an existing PostgreSQL database with a table created like this:
CREATE TABLE product (id SERIAL PRIMARY KEY, name VARCHAR(100) DEFAULT NULL)
This table is described in a YML Doctrine2 file within a Symfony2 project:
Acme\DemoBundle\Entity\Product:
type: entity
table: product
fields:
id:
id: true
type: integer
nullable: false
generator:
strategy: SEQUENCE
name:
type: string
length: 100
nullable: true
When I run for the first time the Doctrine Migrations diff task, I should get a versioning file with no data in the up and down methods. But what I get instead is this :
// ...
class Version20120807125808 extends AbstractMigration
{
public function up(Schema $schema)
{
// this up() migration is autogenerated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() != "postgresql");
$this->addSql("ALTER TABLE product ALTER id DROP DEFAULT");
}
public function down(Schema $schema)
{
// this down() migration is autogenerated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() != "postgresql");
$this->addSql("CREATE SEQUENCE product_id_seq");
$this->addSql("SELECT setval('product_id_seq', (SELECT MAX(id) FROM product))");
$this->addSql("ALTER TABLE product ALTER id SET DEFAULT nextval('product_id_seq')");
}
}
Why are differences detected? How can I avoid this? I tried several sequence strategies with no success.
A little update on this question.
Using Doctrine 2.4, the solution is to use the IDENTITY generator strategy :
Acme\DemoBundle\Entity\Product:
type: entity
table: product
id:
type: integer
generator:
strategy: IDENTITY
fields:
name:
type: string
length: 100
nullable: true
To avoid DROP DEFAULT on fields that have a default value in the database, the default option on the field is the way to go. Of course this can be done with lifecycle callbacks, but it's necessary to keep the default value in the database if this database is used by other apps.
For a "DEFAULT NOW()" like default value, the solution is the following one:
Acme\DemoBundle\Entity\Product:
type: entity
table: product
id:
type: integer
generator:
strategy: IDENTITY
fields:
creation_date:
type: datetime
nullable: false
options:
default: CURRENT_TIMESTAMP
Doctrine 2.0 does not support the SQL DEFAULT keyword, and will always try to drop a postgres default value.
I have found no solution to this problem, I just let doctrine handle the sequences itself.
This is a opened bug registered here :
http://www.doctrine-project.org/jira/browse/DBAL-903