EF7 Code First keeps dropping and recreating foreign keys - entity-framework-core

I'm constantly being notified that 'There are pending model changes for ApplicationDbContext'. The migrations that are being generated appear only to drop a bunch of foreign keys and then recreate them. The following is an example of one where I've made no db changes but have had this message:
public partial class MysteryMigration : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(name: "FK_IdentityRoleClaim<string>_IdentityRole_RoleId", table: "AspNetRoleClaims");
migrationBuilder.DropForeignKey(name: "FK_IdentityUserClaim<string>_User_UserId", table: "AspNetUserClaims");
migrationBuilder.DropForeignKey(name: "FK_IdentityUserLogin<string>_User_UserId", table: "AspNetUserLogins");
migrationBuilder.DropForeignKey(name: "FK_IdentityUserRole<string>_IdentityRole_RoleId", table: "AspNetUserRoles");
migrationBuilder.DropForeignKey(name: "FK_IdentityUserRole<string>_User_UserId", table: "AspNetUserRoles");
migrationBuilder.AddForeignKey(
name: "FK_IdentityRoleClaim<string>_IdentityRole_RoleId",
table: "AspNetRoleClaims",
column: "RoleId",
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_IdentityUserClaim<string>_User_UserId",
table: "AspNetUserClaims",
column: "UserId",
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_IdentityUserLogin<string>_User_UserId",
table: "AspNetUserLogins",
column: "UserId",
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_IdentityUserRole<string>_IdentityRole_RoleId",
table: "AspNetUserRoles",
column: "RoleId",
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_IdentityUserRole<string>_User_UserId",
table: "AspNetUserRoles",
column: "UserId",
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(name: "FK_IdentityRoleClaim<string>_IdentityRole_RoleId", table: "AspNetRoleClaims");
migrationBuilder.DropForeignKey(name: "FK_IdentityUserClaim<string>_User_UserId", table: "AspNetUserClaims");
migrationBuilder.DropForeignKey(name: "FK_IdentityUserLogin<string>_User_UserId", table: "AspNetUserLogins");
migrationBuilder.DropForeignKey(name: "FK_IdentityUserRole<string>_IdentityRole_RoleId", table: "AspNetUserRoles");
migrationBuilder.DropForeignKey(name: "FK_IdentityUserRole<string>_User_UserId", table: "AspNetUserRoles");
migrationBuilder.AddForeignKey(
name: "FK_IdentityRoleClaim<string>_IdentityRole_RoleId",
table: "AspNetRoleClaims",
column: "RoleId",
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
migrationBuilder.AddForeignKey(
name: "FK_IdentityUserClaim<string>_User_UserId",
table: "AspNetUserClaims",
column: "UserId",
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
migrationBuilder.AddForeignKey(
name: "FK_IdentityUserLogin<string>_User_UserId",
table: "AspNetUserLogins",
column: "UserId",
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
migrationBuilder.AddForeignKey(
name: "FK_IdentityUserRole<string>_IdentityRole_RoleId",
table: "AspNetUserRoles",
column: "RoleId",
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
migrationBuilder.AddForeignKey(
name: "FK_IdentityUserRole<string>_User_UserId",
table: "AspNetUserRoles",
column: "UserId",
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
}
}
These foreign keys are dropped + recreated even when I have a legit migration that I need to run. I'm using Microsoft.AspNet.Identity.EntityFramework 3.0.0-rc1-final.
Anyone have any ideas why this is happening, and how I can put an end to it?

Apologies, as per usual the next thing I searched after posting this turned up the answer!
Duplicate question here: "ef migrations add" always recreates foreign keys in the new migration
Basically it's an RC1 issue and will be fixed in the forthcoming RC2

Related

Move Identity Tables To Custom Schema Asp.Net Core

I Try To move all my identity Tables to Schema "User" using the following code in my context. it works fine for all except "AspNetUserClaims", "AspNetRoleClaims". What Should I do?
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<IdentityRole>().ToTable("AspNetRoles", schema: "User");
builder.Entity<IdentityRoleClaim<int>>().ToTable("AspNetRoleClaims", schema: "User");
builder.Entity<ApplicationUser>().ToTable("AspNetUsers", schema: "User");
builder.Entity<IdentityUserClaim<int>>().ToTable("AspNetUserClaims", schema: "User");
builder.Entity<IdentityUserLogin<string>>().ToTable("AspNetUserLogins", schema: "User");
builder.Entity<IdentityUserRole<string>>().ToTable("AspNetUserRoles", schema: "User");
builder.Entity<IdentityUserToken<string>>().ToTable("AspNetUserTokens", schema: "User");
}
Migration Relating to lines above :
using Microsoft.EntityFrameworkCore.Migrations;
namespace MG.Data.Migrations
{
public partial class Mig2 : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.RenameTable(
name: "AspNetUserTokens",
newName: "AspNetUserTokens",
newSchema: "User");
migrationBuilder.RenameTable(
name: "AspNetUsers",
newName: "AspNetUsers",
newSchema: "User");
migrationBuilder.RenameTable(
name: "AspNetUserRoles",
newName: "AspNetUserRoles",
newSchema: "User");
migrationBuilder.RenameTable(
name: "AspNetUserLogins",
newName: "AspNetUserLogins",
newSchema: "User");
migrationBuilder.RenameTable(
name: "AspNetRoles",
newName: "AspNetRoles",
newSchema: "User");
migrationBuilder.CreateTable(
name: "AspNetRoleClaims",
schema: "User",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
RoleId = table.Column<int>(type: "int", nullable: false),
ClaimType = table.Column<string>(type: "nvarchar(max)", nullable: true),
ClaimValue = table.Column<string>(type: "nvarchar(max)", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AspNetUserClaims",
schema: "User",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
UserId = table.Column<int>(type: "int", nullable: false),
ClaimType = table.Column<string>(type: "nvarchar(max)", nullable: true),
ClaimValue = table.Column<string>(type: "nvarchar(max)", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AspNetRoleClaims",
schema: "User");
migrationBuilder.DropTable(
name: "AspNetUserClaims",
schema: "User");
migrationBuilder.RenameTable(
name: "AspNetUserTokens",
schema: "User",
newName: "AspNetUserTokens");
migrationBuilder.RenameTable(
name: "AspNetUsers",
schema: "User",
newName: "AspNetUsers");
migrationBuilder.RenameTable(
name: "AspNetUserRoles",
schema: "User",
newName: "AspNetUserRoles");
migrationBuilder.RenameTable(
name: "AspNetUserLogins",
schema: "User",
newName: "AspNetUserLogins");
migrationBuilder.RenameTable(
name: "AspNetRoles",
schema: "User",
newName: "AspNetRoles");
}
}
}
When ``` base.OnModelCreating(builder); is at the top , moves all except "AspNetUserClaims", "AspNetRoleClaims" . when its at the end it viseversa.
"AspNetUserClaims", "AspNetRoleClaims" check id types you have now in db.
You have problems because thay not the same. In base it should be like:
builder.Entity<IdentityRoleClaim<string>>().ToTable("AspNetRoleClaims", schema: "User");
builder.Entity<IdentityUserClaim<string>>().ToTable("AspNetUserClaims", schema: "User");
If you not set them customly...

Error when running migration on sequelize

'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return Promise.all([
queryInterface.addColumn('Posts', 'userAccountId', {
type: Sequelize.INTEGER,
}),
queryInterface.addColumn('Posts', 'postTopicId', {
type: Sequelize.INTEGER,
}),
queryInterface.addConstraint('Posts', ['userAccountId'], {
type: 'foreign key',
name: 'userAccountId',
references: {
table: 'UserAccounts',
field: 'id',
},
onDelete: 'no action',
onUpdate: 'no action',
}),
queryInterface.addConstraint('Posts', ['postTopicId'], {
type: 'foreign key',
name: 'postTopicId',
references: {
table: 'PostTopics',
field: 'id',
},
onDelete: 'no action',
onUpdate: 'no action',
}),
]);
},
down: (queryInterface, Sequelize) => {
return Promise.all([
queryInterface.removeColumn('Posts', 'userAccountId'),
queryInterface.removeColumn('Posts', 'postTopicId'),
queryInterface.removeConstraint('Posts', 'userAccountId'),
queryInterface.removeConstraint('Posts', 'postTopicId'),
]);
},
};
When I run the command npx sequelize db:migrate, I receive this error "ERROR: column "postTopicId" referenced in foreign key constraint does not exist"
I dont what is wrong, all the other migrations running ok.
I'm running my database in a docker container.
You should not use Promise.all while executing queries that modifying structure and depending on each other. Promise.all does not guarantee an original order of execution queries. Use transaction and sequential execution:
return queryInterface.sequelize.transaction(async transaction => {
await queryInterface.addColumn('Posts', 'userAccountId', {
type: Sequelize.INTEGER,
}, { transaction })
await queryInterface.addColumn('Posts', 'postTopicId', {
type: Sequelize.INTEGER,
}, { transaction })
await queryInterface.addConstraint('Posts', ['userAccountId'], {
type: 'foreign key',
name: 'userAccountId',
references: {
table: 'UserAccounts',
field: 'id',
},
onDelete: 'no action',
onUpdate: 'no action',
}, { transaction })
await queryInterface.addConstraint('Posts', ['postTopicId'], {
type: 'foreign key',
name: 'postTopicId',
references: {
table: 'PostTopics',
field: 'id',
},
onDelete: 'no action',
onUpdate: 'no action',
}, { transaction })
});

An AddColumn was added to migration even though table is unchanged

I have the following model in a EF Core 3 project:
public class MemberModel
{
[Key]
public int Id { get; set; }
[Required, MaxLength(255)]
public string Name { get; set; }
[Required, MaxLength(30)]
public string Phone { get; set; }
[Required, MaxLength(255)]
public string Email { get; set; }
[Required, Display(Name="Company")]
public int CompanyId { get; set; }
public bool isDeleted { get; set; }
}
The CompanyId property was added only in March, and a migration, with timestamp 20200226063529 was done:
public partial class addedCompanyIdColumn : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "CompanyId",
table: "Members",
nullable: false,
defaultValue: 0);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "CompanyId",
table: "Members");
}
}
In the interim, I modified the table to add [Required] attribute to the fields, and I didn't apply any migrations.
Today, I added a migration to do update some other table, and the migration code included code that alters the Members table, adding a CompanyId column, and creating a Companies table that was already there:
migrationBuilder.AlterColumn<string>(
name: "Phone",
table: "Members",
maxLength: 30,
nullable: false,
oldClrType: typeof(string),
oldType: "nvarchar(30)",
oldMaxLength: 30,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "Members",
maxLength: 255,
nullable: false,
oldClrType: typeof(string),
oldType: "nvarchar(255)",
oldMaxLength: 255,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Email",
table: "Members",
maxLength: 255,
nullable: false,
oldClrType: typeof(string),
oldType: "nvarchar(255)",
oldMaxLength: 255,
oldNullable: true);
migrationBuilder.AddColumn<int>(
name: "CompanyId",
table: "Members",
nullable: false,
defaultValue: 0);
migrationBuilder.CreateTable(
name: "Companies",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Name = table.Column<string>(maxLength: 255, nullable: true),
isDeleted = table.Column<bool>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Companies", x => x.Id);
});
So the update failed. I had to go to the database to delete the CompanyId column and the Companies table in order to proceed.
What could have caused this issue, and what should I look out for to avoid such outcomes in future?
Is there a requirement that any changes to the models, no matter how trivial, should be followed by a database update before any transactions are performed?

How to set Many-to-Many relation with custom id name with TypeORM

I have a user, role and user_role table.
When i make #ManyToMany relation i get an error when i try to join the tables because the query uses "roleId" but i named it "role_id" and i cant figure out how to set the column name.
// User.ts
#ManyToMany(type => Role, role => role.users)
#JoinTable({name: 'user_role'})
roles?: Role[];
// Role.ts
#ManyToMany(type => User, user => user.roles)
#JoinTable({name: 'user_role'})
users: User[];
The UserService to query:
public static getAllByRole(role: RoleEnum): Promise<User[]> {
return this.userRepository()
.createQueryBuilder('user')
.leftJoinAndSelect(
'roles',
'role',
'role.user_id = user.id'
).where('role.role_id = :id', {id: role})
.getMany();
}
I expect to get all users with a specific role e.g "Admin".
But it throws an error:
console.log node_modules/typeorm/platform/PlatformTools.js:193
query failed: INSERT INTO "user_role"("roleId", "userId") VALUES ($1, DEFAULT), ($2, DEFAULT) -- PARAMETERS: ["ROLE_ADMIN","ROLE_USER"]
console.log node_modules/typeorm/platform/PlatformTools.js:193
error: { error: column "roleId" of relation "user_role" does not exist
I found it:
// User.ts
#Field(type => [Role])
#ManyToMany(type => Role, role => role.users)
#JoinTable({
name: 'user_role', joinColumn: {
name: 'user_id',
referencedColumnName: 'id'
},
inverseJoinColumn: {
name: 'role_id',
referencedColumnName: 'id'
}
})
roles?: Role[];
// Role.ts
#ManyToMany(type => User, user => user.roles)
#JoinTable({
name: 'user_role',
joinColumn: {
name: 'role_id',
referencedColumnName: 'id'
},
inverseJoinColumn: {
name: 'user_id',
referencedColumnName: 'id'
}
})
users: User[];

How to generate right migration on changed table names Asp.NET Core IdentityUser etc

It is possible to change table names of the IdentityUser, IdentityRole,... tables.
See How can I change the table names when using Visual Studio 2013 ASP.NET Identity?
protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<IdentityUser>().ToTable("MyUsers");
}
But when I create new migration:
dotnet ef migrations add new ApplicationIdentity
The migration is generated for the original names:
migrationBuilder.CreateTable(
name: "AspNetUsers",
columns: table => new
{
Id = table.Column<long>(nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
AccessFailedCount = table.Column<int>(nullable: false),
ConcurrencyStamp = table.Column<string>(nullable: true),
Email = table.Column<string>(maxLength: 256, nullable: true),
EmailConfirmed = table.Column<bool>(nullable: false),
LockoutEnabled = table.Column<bool>(nullable: false),
LockoutEnd = table.Column<DateTimeOffset>(nullable: true),
NormalizedEmail = table.Column<string>(maxLength: 256, nullable: true),
NormalizedUserName = table.Column<string>(maxLength: 256, nullable: true),
PasswordHash = table.Column<string>(nullable: true),
PhoneNumber = table.Column<string>(nullable: true),
PhoneNumberConfirmed = table.Column<bool>(nullable: false),
SecurityStamp = table.Column<string>(nullable: true),
TwoFactorEnabled = table.Column<bool>(nullable: false),
UserName = table.Column<string>(maxLength: 256, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUsers", x => x.Id);
});
It is possible to change generated migration manually, but is there any trick how to generate migration with correct names?
You need to add the migration manually:
Add Empty migration file by using the below command
dotnet ef migrations add rename_tables
A new file will add to migration and you need to change it as the below
public partial class rename_tables : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.RenameTable(name: "AspNetRoleClaims", newName: "RoleClaims");
migrationBuilder.RenameTable(name: "AspNetRoles", newName: "Roles");
migrationBuilder.RenameTable(name: "AspNetUserLogins", newName: "UserLogins");
migrationBuilder.RenameTable(name: "AspNetUserRoles", newName: "UserRoles");
migrationBuilder.RenameTable(name: "AspNetUsers", newName: "Users");
migrationBuilder.RenameTable(name: "AspNetUserTokens", newName: "UserTokens");
migrationBuilder.RenameTable(name: "AspNetUserClaims", newName: "UserClaims");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.RenameTable(name: "RoleClaims", newName: "AspNetRoleClaims");
migrationBuilder.RenameTable(name: "Roles", newName: "AspNetRoles");
migrationBuilder.RenameTable(name: "UserLogins", newName: "AspNetUserLogins");
migrationBuilder.RenameTable(name: "UserRoles", newName: "AspNetUserRoles");
migrationBuilder.RenameTable(name: "Users", newName: "AspNetUsers");
migrationBuilder.RenameTable(name: "UserTokens", newName: "AspNetUserTokens");
migrationBuilder.RenameTable(name: "AspNetUserClaims", newName: "AspNetUserClaims");
}
}
Finally you need to apply the migration
dotnet ef database update
This is will not change the constraints name but you can also added to you migration file
You can do this on your DbContext:
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<ApplicationUser>(entity =>
{
entity.ToTable(name: "Users");
entity.Property(e => e.Id).HasColumnName("UserId");
});
}
Will create this migration:
migrationBuilder.CreateTable(
name: "Users",
columns: table => new
{
UserId = table.Column<string>(nullable: false),
AccessFailedCount = table.Column<int>(nullable: false),
ConcurrencyStamp = table.Column<string>(nullable: true),
Email = table.Column<string>(maxLength: 256, nullable: true),
EmailConfirmed = table.Column<bool>(nullable: false),
LockoutEnabled = table.Column<bool>(nullable: false),
LockoutEnd = table.Column<DateTimeOffset>(nullable: true),
NormalizedEmail = table.Column<string>(maxLength: 256, nullable: true),
NormalizedUserName = table.Column<string>(maxLength: 256, nullable: true),
PasswordHash = table.Column<string>(nullable: true),
PhoneNumber = table.Column<string>(nullable: true),
PhoneNumberConfirmed = table.Column<bool>(nullable: false),
SecurityStamp = table.Column<string>(nullable: true),
TwoFactorEnabled = table.Column<bool>(nullable: false),
UserName = table.Column<string>(maxLength: 256, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Users", x => x.UserId);
});