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...
Related
I have a basic nestjs app with 3 entities :
document: DocumentEntity has pages: PageEntity[] as #OneToMany relation
page: PageEntity has words: WordEntity[]as #OneToMany relation + #ManyToOne document
word: WordEntity has a #ManyToOne page: PageEntity
This is quite straightforward and the first part of those relations works as expected :
I can save new pages doing so :
async createPage(documentId: number, url: string) {
const document = await this.documentRepository.findOne({ id: documentId });
if (document) {
const pageEntity = new PageEntity();
pageEntity.imgUrl = url;
pageEntity.document = document;
await this.pageRepository.save(pageEntity);
}
}
but when I try to apply the same logic to the words/page relation, it fails. I m not sure why this behaves differently
async postWord(pageId: number, word: { text: string }) {
const page = await this.pageRepository.findOne({ id: pageId });
if (page) {
const wordEntity = new WordEntity();
wordEntity.text = word.text;
wordEntity.page = page;
await this.wordRepository.save(wordEntity);
}
}
Error Message :
[ExceptionsHandler] null value in column "pageId" of relation "word_entity" violates not-null constraint +107723ms
QueryFailedError: null value in column "pageId" of relation "word_entity" violates not-null constraint
here are the entities declarations :
// document.entity.ts
#Entity()
class DocumentEntity {
#PrimaryGeneratedColumn()
public id?: number;
#Column()
public name: string;
#Column()
public locale: string;
#Column()
public pdfUrl: string;
#Column()
public folderPath: string;
#OneToMany(() => PageEntity, (page) => page.document, {
primary: true,
eager: true,
cascade: true,
})
public pages?: PageEntity[];
}
export default DocumentEntity;
// page.entity.ts
#Entity()
class PageEntity {
#PrimaryGeneratedColumn()
public id?: number;
#Column({ nullable: true })
public pageNumber?: number;
#Column({ nullable: true })
public text?: string;
#Column()
public imgUrl: string;
#OneToMany(() => WordEntity, (word) => word.page, {
eager: true,
onDelete: 'CASCADE',
primary: true,
})
words?: WordEntity[];
#ManyToOne(() => DocumentEntity, {
primary: true,
onDelete: 'CASCADE',
})
#JoinColumn()
public document: DocumentEntity;
}
export default PageEntity;
// word.entity.ts
#Entity()
class WordEntity {
#PrimaryGeneratedColumn()
public id?: number;
#ManyToOne(() => PageEntity, {
nullable: true,
primary: true,
onDelete: 'CASCADE',
})
#JoinColumn()
public page!: PageEntity;
#Column()
public text: string;
#Column({ type: 'decimal', nullable: true })
public confidence?: number;
}
Try this:
#Entity()
class WordEntity {
.....
#ManyToOne(() => PageEntity, {
nullable: true,
primary: true,
onDelete: 'CASCADE',
})
#JoinColumn({
name: 'pageId',
referencedColumnName: 'id',
})
page?: PageEntity;
#Column({ nullable: true })
pageId?: number
.....
}
async postWord(pageId: number, word: { text: string }) {
const wordEntity = new WordEntity();
wordEntity.text = word.text;
// check if the pageId exists, maybe inside Dto with a decorator
wordEntity.pageId = pageId;
await this.wordRepository.save(wordEntity);
}
You need to remove the primary: true from your #ManyToOne relation because a primary relation cannot be set as NULL
App in development, using Postgres, docker, and typeorm. Terminal shots error as if migration did not run, and says "relation 'orphanages' already exist".
But my database client tool beekeper shows all migrations were created just fine, and api is receiving data normaly in all routes.
Anyone has any clue what s happening?
ormconfig.json
{
"type": "postgres",
"host": "localhost",
"port": 5432,
"username": "postgres",
"password": "docker",
"database": "happy",
"synchronize": true,
"migrations": [
"./src/database/migrations/*.ts"
],
"entities": [
"./src/models/*.ts"
],
"cli": {
"migrationsDir": "./src/database/migrations"
}
}
migration file:
import {MigrationInterface, QueryRunner, Table} from "typeorm";
export class Orphanage1616788509901 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(new Table({
name: 'orphanages',
columns: [
{
name: 'id',
type: 'uuid',
unsigned: true,
isPrimary: true,
isGenerated: true,
},
{
name: 'name',
type: 'varchar'
},
{
name: 'latitude',
type: 'varchar'
},
{
name: 'longitude',
type: 'varchar'
},
{
name: 'about',
type: 'text'
},
{
name: 'instructions',
type: 'text'
},
{
name: 'opening_hours',
type: 'varchar'
},
{
name: 'open_on_weekends',
type: 'boolean',
default: 'false'
},
{
name: 'user_name',
type: 'varchar'
},
{
name: 'user_id',
type: 'uuid'
}
],
foreignKeys: [
{
name: 'OrphanageUser',
columnNames: ['user_id'],
referencedTableName: 'users',
referencedColumnNames: ['id'],
onUpdate: 'CASCADE',
onDelete: 'CASCADE',
}
]
}))
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('orphanages');
}
}
entity file
import { Entity, Column, PrimaryGeneratedColumn, OneToMany, JoinColumn, ManyToOne } from 'typeorm';
import Image from './Images';
import User from './User';
#Entity('orphanages')
export default class Orphanage {
#PrimaryGeneratedColumn('uuid')
id: number;
#Column()
name: string;
#Column()
latitude: string;
#Column()
longitude: string;
#Column()
about: string;
#Column()
instructions: string;
#Column()
opening_hours: string;
#Column()
open_on_weekends: boolean;
#Column()
user_id: number;
#Column()
user_name: string;
#OneToMany(() => Image, image => image.orphanage, {
cascade: ['insert' , 'update']
})
#JoinColumn({ name: 'orphanage_id'})
images: Image[];
#ManyToOne(() => User, user => user.orphanages)
#JoinColumn({ name: 'user_id'})
user: User;
}
user migration file
import {MigrationInterface, QueryRunner, Table} from "typeorm";
export class User1616788592127 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(new Table({
name: 'users',
columns: [
{
name: 'id',
type: 'uuid',
unsigned: true,
isPrimary: true,
isGenerated: true,
// generationStrategy:'increment'
},
{
name: 'name',
type: 'varchar'
},
{
name: 'email',
type: 'varchar',
isUnique: true
},
{
name: 'password',
type: 'varchar',
},
{
name: 'role',
type: 'varchar',
},
{
name: "date",
type: "timestamp",
},
{
name: "isVerified",
type: "boolean",
default: false,
},
{
name: "tokenId",
type: "uuid",
// default: false,
},
],
foreignKeys: [
{
name: 'TokenUser',
columnNames: ['tokenId'],
referencedTableName: 'tokens',
referencedColumnNames: ['id'],
onUpdate: 'CASCADE',
onDelete: 'CASCADE',
}
]
}))
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('users');
}
}
user entity file
import { Request, Response } from 'express';
import { Entity, Column, PrimaryGeneratedColumn, BeforeInsert, BeforeUpdate, OneToMany, OneToOne, JoinColumn, CreateDateColumn, UpdateDateColumn, createConnection } from 'typeorm'; // decorators from typeorm
// import { Length, IsNotEmpty } from 'class-validator';
import * as bcrypt from 'bcryptjs';
import Orphanage from './Orphanage';
import Token from './Token';
#Entity('users')
export default class User {
#PrimaryGeneratedColumn('uuid')
id: number;
#Column()
name: string;
#Column({
unique: true
})
email: string;
#Column()
password: string;
#Column()
role: string;
default: 'basic'
enum: ["basic", "supervisor", "admin"];
#Column({
type: "timestamp"
})
date!: Date;
#Column({
default: false
})
isVerified: boolean;
checkIfUnencryptedPasswordIsValid(unencryptedPassword: string) {
return bcrypt.compareSync(unencryptedPassword, this.password);
}
#OneToMany(() => Orphanage, orphanage => orphanage.user, {
cascade: ['insert' , 'update']
})
#JoinColumn({ name: 'user_id'})
orphanages: Orphanage[];
#OneToOne(() => Token, token => token.user, {
// cascade: ['insert' , 'update'] //
})
#JoinColumn({name: "tokenId"})
// token: Token[];
token: Token;
}
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?
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);
});
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