EF Migration is generating a second index for the aggregate PK - sql-server

I am trying to create a new migration for my project and i just depared with an awkward situation... I have my aggregate root entity:
public class Classroom : Entity, IAggregateRoot
{
// PK
public int ClassroomId { get; set; }
// ....
public virtual ClassroomStreaming Streaming { get; set; }
}
And the aggregate:
public class ClassroomStreaming : Entity
{
// PK
public int ClassroomId { get; set; }
public virtual Classroom Classroom { get; set; }
// Fields
public string EmbedCode { get; set; }
// ...
}
The mappings are:
public class ClassroomMap : EntityTypeConfiguration<Classroom>
{
public ClassroomMap()
{
this.HasKey(t => t.ClassroomId);
this.ToTable("Classroom");
// ....
// One to One
this.HasOptional(t => t.Streaming)
.WithRequired(p => p.Classroom);
}
}
and:
public class ClassroomStreamingMap: EntityTypeConfiguration<ClassroomStreaming>
{
public ClassroomStreamingMap()
{
// Primary Key
this.HasKey(t => new { t.ClassroomId });
// Table & Column Mappings
this.ToTable("ClassroomStreaming");
this.Property(t => t.ClassroomId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
// Relationships
this.HasRequired(t => t.Classroom)
.WithOptional(p => p.Streaming)
.WillCascadeOnDelete(true);
}
}
When I generate the migration, i get the following situation where it creates the PK and also an non clustered index for the same column:
public override void Up()
{
CreateTable(
"dbo.ClassroomStreaming",
c => new
{
ClassroomId = c.Int(nullable: false),
// ....
})
.PrimaryKey(t => t.ClassroomId)
.ForeignKey("dbo.Classroom", t => t.ClassroomId, cascadeDelete: true)
.Index(t => t.ClassroomId);
}
Is it a normal behavior? look how it is in the SQL Server:

It looks like based you have "double-mapped" your relationships in the two EntityTypeConfiguration<T> classes. I think you only need to define the relationship in one direction.
The Entity Framework Fluent API documentation states that for one-to-zero-or-one relationships, define it with .HasOptional().WithRequired() as you have done in the ClassroomMap. You should be able remove the .HasRequired().WithOptional() in the ClassroomStreamingMap class.

Related

How to relate Abpuser Table to other tables ABP Webframework

I have a requirement. There are 3 types of users
Social User
Influencer
Business User
These three users need to be linked to same AbpUser Table. Something like. One AbpUser has one to one relationship with Social, Influencer and Business user. Right now I am not able to make the Social user having reference to Abpuser. same with other user types.
I have the Following classes,
public class SocialUser : FullAuditedAggregateRoot<Guid>
{
public Guid AppUserId { get; set; }// Foreign key referenceing the Appuser
public string DisplayName { get; set; }
// Other code block removed for clarity
}
And Appuser Table like this,
public class AppUser : FullAuditedAggregateRoot<Guid>, IUser
{
public string UserName { get; set; }
public string Email { get; set; }
// ..... Other code block removed for clarity.
}
builder.Entity<AppUser>(u =>
{
u.ToTable(AbpIdentityDbProperties.DbTablePrefix + "Users"); //Sharing the same table "AbpUsers" with the IdentityUser
u.ConfigureByConvention();
u.ConfigureAbpUser();
u.HasOne<SocialUser>().WithOne().HasForeignKey<SocialUser>(x => x.AppUserId).IsRequired();
});
// Other code blocks removed for clarity
}
But while running the Migrations, the AppSocialUser doesn't have foreign key constraint referring to AppUser.
Any ideas, Please let me know. Your valuable suggestions and input make my life easy. Struggling for the past one week. Thank you.
Try:
Entity:
public class SocialUser : FullAuditedAggregateRoot<Guid>
{
public Guid UserId { get; set; }
public string DisplayName { get; set; }
//...
}
DbContextModelCreatingExtensions:
builder.Entity<SocialUser>(b =>
{
b.ConfigureByConvention();
});
MyProjectNameDbContext:
builder.Entity<SocialUser>(b =>
{
b.HasOne<AppUser>().WithMany().HasForeignKey(x => x.UserId);
});
MyProjectNameMigrationsDbContext:
builder.Entity<SocialUser>(b =>
{
b.HasOne<IdentityUser>().WithMany().HasForeignKey(x => x.UserId);
});
Entity:
public class Influencer : FullAuditedAggregateRoot<Guid>
{
public Guid AppUserId { get; set; }// Foreign key referenceing the Appuser
[ForeignKey(nameof(AppUserId))]
public AppUser AppUser { get; set; }
public string DisplayName { get; set; }
}
MyProjectNameMigrationsDbContext :
builder.Entity<AppUser>(b =>
{
b.ToTable("AbpUsers");
b.ConfigureAbpUser();
b.ConfigureFullAuditedAggregateRoot();
b.HasOne<IdentityUser>().WithOne().HasForeignKey<AppUser>(e => e.Id);
b.ConfigureCustomUserProperties();
});

EF 6 and many to many relationship [duplicate]

This question already has answers here:
Create code first, many to many, with additional fields in association table
(7 answers)
Closed 2 years ago.
i m working on EF 6 (mapping with many to many relationship) ,see
https://www.codeproject.com/Articles/234606/Creating-a-Many-To-Many-Mapping-Using-Code-First
where it created "PersonCourses"  as middle table ,now i have two problem with that In a many-to-many relationship EF manages the join table internally and hidden. It's a table without an Entity class in your model. 
so what if i need to access "PersonCourses"   in my code (project) and what if i  need to add certain columns with it ??
EF can auto-manage the joining table so long as it just contains the two FKs as a composite PK. If you want to add to that then you need to declare the joining table as an entity with a one-to-many from each side.
So instead of:
[Table("Persons")]
public class Person
{
// ...
public virtual ICollection<Course> Courses { get; set; } = new List<Course>();
}
[Table("Courses")]
public class Course
{
// ...
public virtual ICollection<Person> People { get; set; } = new List<Person>();
}
modelBuilder.Entity<Person>()
.HasMany(x => x.Courses)
.WithMany(x => x.People);
you would have:
[Table("Persons")]
public class Person
{
// ...
public virtual ICollection<PersonCourse> PersonCourses { get; set; } = new List<PersonCourse>();
}
[Table("Courses")]
public class Course
{
// ...
public virtual ICollection<PersonCourse> PersonCourses { get; set; } = new List<PersonCourse>();
}
[Table("PersonCourses")]
public class PersonCourse
{
[Key, Column(Order=0), ForeignKey("Person")]
public int PersonId { get; set; }
[Key, Column(Order=1), ForeignKey("Course")]
public int CourseId { get; set; }
// ... any additional properties for the entity.
public virtual Person Person { get; set; }
public virtual Course Course { get; set; }
}
modelBuilder.Entity<Person>()
.HasMany(x => x.PersonCourses)
.WithRequired(x => x.Person);
modelBuilder.Entity<Course>()
.HasMany(x => x.PersonCourses)
.WithRequired(x => x.Course);
The main disadvantage of this is that Person no longer has a collection of Courses, but of PersonCourses so you have to dive the extra level in your projections every time you want to get details about course names. It might be tempting to leave the PersonCourses collection on Person named as "Courses" but I found that this can get misleading as you can end up with collections on some objects called Persons being Person vs. PersonCourse or Courses being Course vs. PersonCourse. It's generally less confusing when the collection name reflects the type.
So instead of:
var courses = context.Persons
.Where(x => x.PersonId == personId)
.SelectMany(x => x.Courses)
.ToList();
You need to change that to:
var courses = context.Persons
.Where(x => x.PersonId == personId)
.SelectMany(x => x.PersonCourses.Select(pc => pc.Course))
.ToList();
Update: To have an Id column on PersonCourse:
[Table("PersonCourses")]
public class PersonCourse
{
[Key]
public int Id { get; set; }
[ForeignKey("Person")]
public int PersonId { get; set; }
[ForeignKey("Course")]
public int CourseId { get; set; }
// ... any additional properties for the entity.
public virtual Person Person { get; set; }
public virtual Course Course { get; set; }
}
... or better, do away with the FK fields in the entity and map them via configuration:
[Table("PersonCourses")]
public class PersonCourse
{
[Key]
public int Id { get; set; }
// ... any additional properties for the entity.
public virtual Person Person { get; set; }
public virtual Course Course { get; set; }
}
EF6 may map these automatically by convention, but explicitly you can use:
modelBuilder.Entity<Person>()
.HasMany(x => x.PersonCourses)
.WithRequired(x => x.Person)
.Map(x => x.Mpakey("PersonId");
modelBuilder.Entity<Course>()
.HasMany(x => x.PersonCourses)
.WithRequired(x => x.Course)
.Map(x => x.Mpakey("CourseId");
I recommend this approach, like Shadow Properties with EF Core to avoid having 2 sources of truth for the Person ID or Course ID.
I.e. PersonCourse.PersonId vs. PersonCourse.Person.Id
When updating entities with navigation properties, you should update references via the navigation property, (personCourse.Course = newCourse) not via a FK property. (personCourse.CourseId = newCourseId) Doing so, or intermixing the source of truth for the FK can lead to weird results depending on what the DbContext is tracking at the time.

Re-Creating table in migration results in 'Invalid column name User_Id'

I open this question because of this unanswered/duplicate question of mine:
Multiple identity columns specified for table exception
The answer to this question is here:
Cant remove identity attribute from PK
in short: "I have to Re-Create my sql table in the migration Up method"
I have a User has many SchoolclassCode relation:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<SchoolclassCode> SchoolclassCodes { get; set; }
}
public class SchoolclassCode
{
public int Id { get; set; }
public string Schoolclass { get; set; }
public string Type { get; set; }
public User User { get; set; }
public int UserId { get; set; }
}
That is my INIT migration
public partial class Init: DbMigration
{
public override void Up()
{
CreateTable(
"dbo.SchoolclassCodes",
c => new
{
Id = c.Int(nullable: false, identity: true),
Schoolclass = c.String(),
Type = c.String(),
User_Id = c.Int(),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.Users", t => t.User_Id)
.Index(t => t.User_Id);
CreateTable(
"dbo.Users",
c => new
{
Id = c.Int(nullable: false, identity: true),
Name = c.String(),
})
.PrimaryKey(t => t.Id);
}
public override void Down()
{
DropForeignKey("dbo.SchoolclassCodes", "User_Id", "dbo.Users");
DropIndex("dbo.SchoolclassCodes", new[] { "User_Id" });
DropTable("dbo.Users");
DropTable("dbo.SchoolclassCodes");
}
}
That is my Second migration which is throwing the error: invalid column name 'User_Id' when I do 'Update-database'
public partial class ReCreateTable : DbMigration
{
public override void Up()
{
// backup schoolclassCodes table
DropTable("SchoolclassCodes");
CreateTable("SchoolclassCodes",
c => new
{
Id = c.Int(nullable: false, identity: true),
Schoolclass = c.String(maxLength: 3), // 12a,7b
Type = c.String(),
UserId = c.Int(nullable: false,identity:false)
})
.PrimaryKey(t => t.Id)
.ForeignKey("Users", t => t.UserId, cascadeDelete: true)
.Index(s => s.Schoolclass, unique: true);
// Delete Table Users
Sql("Delete from Users");
// Re-Insert data
SqlFile("./Migrations/data.sql");
}
public override void Down()
{
//
}
}
What do I wrong, that the update-database fails?
If you are going to delete everything you created in the first migration, drop them as described in the Down() code:
// backup schoolclassCodes table
DropForeignKey("dbo.SchoolclassCodes", "User_Id", "dbo.Users");
DropIndex("dbo.SchoolclassCodes", new[] { "User_Id" });
// DropTable("dbo.Users");
DropTable("dbo.SchoolclassCodes");
An observation, seems like you are coupling the need to keep your old data with migrations. I would separate the two.
First, save your old data. If the volume is low consider adding it to a Seed() method. Otherwise rename the tables in SQL and use SQL to repopulate them after migrations adds the corrected tables back.
Migrations are intended to let you build a database from your models, so I would delete both migrations and add a single new migration that represents your current model.

Need some help to interpret error message [duplicate]

I've been wrestling with this for a while and can't quite figure out what's happening. I have a Card entity which contains Sides (usually 2) - and both Cards and Sides have a Stage. I'm using EF Codefirst migrations and the migrations are failing with this error:
Introducing FOREIGN KEY constraint 'FK_dbo.Sides_dbo.Cards_CardId' on
table 'Sides' may cause cycles or multiple cascade paths. Specify ON
DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY
constraints.
Here's my Card entity:
public class Card
{
public Card()
{
Sides = new Collection<Side>();
Stage = Stage.ONE;
}
[Key]
[Required]
public virtual int CardId { get; set; }
[Required]
public virtual Stage Stage { get; set; }
[Required]
[ForeignKey("CardId")]
public virtual ICollection<Side> Sides { get; set; }
}
Here's my Side entity:
public class Side
{
public Side()
{
Stage = Stage.ONE;
}
[Key]
[Required]
public virtual int SideId { get; set; }
[Required]
public virtual Stage Stage { get; set; }
[Required]
public int CardId { get; set; }
[ForeignKey("CardId")]
public virtual Card Card { get; set; }
}
And here's my Stage entity:
public class Stage
{
// Zero
public static readonly Stage ONE = new Stage(new TimeSpan(0, 0, 0), "ONE");
// Ten seconds
public static readonly Stage TWO = new Stage(new TimeSpan(0, 0, 10), "TWO");
public static IEnumerable<Stage> Values
{
get
{
yield return ONE;
yield return TWO;
}
}
public int StageId { get; set; }
private readonly TimeSpan span;
public string Title { get; set; }
Stage(TimeSpan span, string title)
{
this.span = span;
this.Title = title;
}
public TimeSpan Span { get { return span; } }
}
What's odd is that if I add the following to my Stage class:
public int? SideId { get; set; }
[ForeignKey("SideId")]
public virtual Side Side { get; set; }
The migration runs successfully. If I open up SSMS and look at the tables, I can see that Stage_StageId has been added to Cards (as expected/desired), however Sides contains no reference to Stage (not expected).
If I then add
[Required]
[ForeignKey("StageId")]
public virtual Stage Stage { get; set; }
public int StageId { get; set; }
To my Side class, I see StageId column added to my Side table.
This is working, but now throughout my application, any reference to Stage contains a SideId, which is in some cases totally irrelevant. I'd like to just give my Card and Side entities a Stage property based on the above Stage class without polluting the stage class with reference properties if possible... what am I doing wrong?
Because Stage is required, all one-to-many relationships where Stage is involved will have cascading delete enabled by default. It means, if you delete a Stage entity
the delete will cascade directly to Side
the delete will cascade directly to Card and because Card and Side have a required one-to-many relationship with cascading delete enabled by default again it will then cascade from Card to Side
So, you have two cascading delete paths from Stage to Side - which causes the exception.
You must either make the Stage optional in at least one of the entities (i.e. remove the [Required] attribute from the Stage properties) or disable cascading delete with Fluent API (not possible with data annotations):
modelBuilder.Entity<Card>()
.HasRequired(c => c.Stage)
.WithMany()
.WillCascadeOnDelete(false);
modelBuilder.Entity<Side>()
.HasRequired(s => s.Stage)
.WithMany()
.WillCascadeOnDelete(false);
I had a table that had a circular relationship with others and I was getting the same error. Turns out it is about the foreign key which was not nullable. If the key is not nullable the related object must be deleted, and circular relations don't allow that. So use nullable foreign key.
[ForeignKey("StageId")]
public virtual Stage Stage { get; set; }
public int? StageId { get; set; }
Anybody wondering how to do it in EF core:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
foreach (var relationship in modelBuilder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys()))
{
relationship.DeleteBehavior = DeleteBehavior.Restrict;
}
..... rest of the code.....
I was getting this error for lots of entities when I was migrating down from an EF7 model to an EF6 version. I didn't want to have to go through each entity one at a time, so I used:
builder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
builder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
You can set cascadeDelete to false or true (in your migration Up() method). Depends upon your requirement.
AddForeignKey("dbo.Stories", "StatusId", "dbo.Status", "StatusID", cascadeDelete: false);
In .NET Core I changed the onDelete option to ReferencialAction.NoAction
constraints: table =>
{
table.PrimaryKey("PK_Schedule", x => x.Id);
table.ForeignKey(
name: "FK_Schedule_Teams_HomeId",
column: x => x.HomeId,
principalTable: "Teams",
principalColumn: "Id",
onDelete: ReferentialAction.NoAction);
table.ForeignKey(
name: "FK_Schedule_Teams_VisitorId",
column: x => x.VisitorId,
principalTable: "Teams",
principalColumn: "Id",
onDelete: ReferentialAction.NoAction);
});
I had this issue also, I solved it instantly with this answer from a similar thread
In my case, I didn't want to delete the dependent record on key deletion. If this is the case in your situation just simply change the Boolean value in the migration to false:
AddForeignKey("dbo.Stories", "StatusId", "dbo.Status", "StatusID", cascadeDelete: false);
Chances are, if you are creating relationships which throw this compiler error but DO want to maintain cascade delete; you have an issue with your relationships.
I fixed this. When you add the migration, in the Up() method there will be a line like this:
.ForeignKey("dbo.Members", t => t.MemberId, cascadeDelete:True)
If you just delete the cascadeDelete from the end it will work.
Just for documentation purpose, to someone that comes on the future, this thing can be solved as simple as this, and with this method, you could do a method that disabled one time, and you could access your method normally
Add this method to the context database class:
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
}
In .NET Core I played with all upper answers - but without any success.
I made changes a lot in DB structure and every time added new migration attempting to update-database, but received the same error.
Then I started to remove-migration one by one until Package Manager Console threw me exception:
The migration '20170827183131_***' has already been applied to the database
After that, I added new migration (add-migration) and update-database successfully
So my suggestion would be: clear out all your temp migrations, until your current DB state.
public partial class recommended_books : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.RecommendedBook",
c => new
{
RecommendedBookID = c.Int(nullable: false, identity: true),
CourseID = c.Int(nullable: false),
DepartmentID = c.Int(nullable: false),
Title = c.String(),
Author = c.String(),
PublicationDate = c.DateTime(nullable: false),
})
.PrimaryKey(t => t.RecommendedBookID)
.ForeignKey("dbo.Course", t => t.CourseID, cascadeDelete: false) // was true on migration
.ForeignKey("dbo.Department", t => t.DepartmentID, cascadeDelete: false) // was true on migration
.Index(t => t.CourseID)
.Index(t => t.DepartmentID);
}
public override void Down()
{
DropForeignKey("dbo.RecommendedBook", "DepartmentID", "dbo.Department");
DropForeignKey("dbo.RecommendedBook", "CourseID", "dbo.Course");
DropIndex("dbo.RecommendedBook", new[] { "DepartmentID" });
DropIndex("dbo.RecommendedBook", new[] { "CourseID" });
DropTable("dbo.RecommendedBook");
}
}
When your migration fails you are given a couple of options:
'Introducing FOREIGN KEY constraint 'FK_dbo.RecommendedBook_dbo.Department_DepartmentID' on table 'RecommendedBook' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint or index. See previous errors.'
Here is an example of using the 'modify other FOREIGN KEY constraints' by setting 'cascadeDelete' to false in the migration file and then run 'update-database'.
Make your Foreign key attributes nullable. That will work.
This sounds weird and I don't know why, but in my case that was happening because my ConnectionString was using "." in "data source" attribute. Once I changed it to "localhost" it workded like a charm. No other change was needed.
The existing answers are great I just wanted to add that I ran into this error because of a different reason. I wanted to create an Initial EF migration on an existing DB but I didn't use the -IgnoreChanges flag and applied the Update-Database command on an empty Database (also on the existing fails).
Instead I had to run this command when the current db structure is the current one:
Add-Migration Initial -IgnoreChanges
There is likely a real problem in the db structure but save the world one step at a time...
In .NET 5 < and .NET Core 2.0 < you can use .OnDelete(DeleteBehavior.Restrict) in OnModelCreating like #Nexus23 answer but you do not need to disable cascade for every model.
Example with join entity type configuration many-to-many:
internal class MyContext : DbContext
{
public MyContext(DbContextOptions<MyContext> options)
: base(options)
{
}
public DbSet<Post> Posts { get; set; }
public DbSet<Tag> Tags { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Post>()
.HasMany(p => p.Tags)
.WithMany(p => p.Posts)
.UsingEntity<PostTag>(
j => j
.HasOne(pt => pt.Tag)
.WithMany(t => t.PostTags)
.HasForeignKey(pt => pt.TagId)
.OnDelete(DeleteBehavior.Restrict),
j => j
.HasOne(pt => pt.Post)
.WithMany(p => p.PostTags)
.HasForeignKey(pt => pt.PostId)
.OnDelete(DeleteBehavior.Restrict),
j =>
{
j.Property(pt => pt.PublicationDate).HasDefaultValueSql("CURRENT_TIMESTAMP");
j.HasKey(t => new { t.PostId, t.TagId });
});
}
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public ICollection<Tag> Tags { get; set; }
public List<PostTag> PostTags { get; set; }
}
public class Tag
{
public string TagId { get; set; }
public ICollection<Post> Posts { get; set; }
public List<PostTag> PostTags { get; set; }
}
public class PostTag
{
public DateTime PublicationDate { get; set; }
public int PostId { get; set; }
public Post Post { get; set; }
public string TagId { get; set; }
public Tag Tag { get; set; }
}
Sources:
https://learn.microsoft.com/en-us/ef/core/modeling/relationships?tabs=fluent-api%2Cfluent-api-simple-key%2Csimple-key#join-entity-type-configuration
https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.deletebehavior?view=efcore-5.0
This does require you to remove the many to many relationship yourself or you will receive the following error when you remove a parent entity:
The association between entity types '' and '' has been severed, but
the relationship is either marked as required or is implicitly
required because the foreign key is not nullable. If the
dependent/child entity should be deleted when a required relationship
is severed, configure the relationship to use cascade deletes.
Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to
see the key values
You can solve this by using DeleteBehavior.ClientCascade instead which will allow EF to perform cascade deletes on loaded entities.
internal class MyContext : DbContext
{
public MyContext(DbContextOptions<MyContext> options)
: base(options)
{
}
public DbSet<Post> Posts { get; set; }
public DbSet<Tag> Tags { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Post>()
.HasMany(p => p.Tags)
.WithMany(p => p.Posts)
.UsingEntity<PostTag>(
j => j
.HasOne(pt => pt.Tag)
.WithMany(t => t.PostTags)
.HasForeignKey(pt => pt.TagId)
.OnDelete(DeleteBehavior.Cascade),
j => j
.HasOne(pt => pt.Post)
.WithMany(p => p.PostTags)
.HasForeignKey(pt => pt.PostId)
.OnDelete(DeleteBehavior.ClientCascade),
j =>
{
j.Property(pt => pt.PublicationDate).HasDefaultValueSql("CURRENT_TIMESTAMP");
j.HasKey(t => new { t.PostId, t.TagId });
});
}
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public ICollection<Tag> Tags { get; set; }
public List<PostTag> PostTags { get; set; }
}
public class Tag
{
public string TagId { get; set; }
public ICollection<Post> Posts { get; set; }
public List<PostTag> PostTags { get; set; }
}
public class PostTag
{
public DateTime PublicationDate { get; set; }
public int PostId { get; set; }
public Post Post { get; set; }
public string TagId { get; set; }
public Tag Tag { get; set; }
}
https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.deletebehavior?view=efcore-5.0
None of the aforementioned solutions worked for me. What I had to do was use a nullable int (int?) on the foreign key that was not required (or not a not null column key) and then delete some of my migrations.
Start by deleting the migrations, then try the nullable int.
Problem was both a modification and model design. No code change was necessary.
The simple way is to, Edit your migration file (cascadeDelete: true) into (cascadeDelete: false) then after assign the Update-Database command in your Package Manager Console.if it's problem with your last migration then all right. Otherwise check your earlier migration history, copy those things, paste into your last migration file, after that do it the same thing. it perfectly works for me.
You could add this in your DataContext.cs, this works for me...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
}
I ran into the same problem and stuck for a long. The following steps saved me.
Go through the constraints and change the onDelete ReferentialAction to NoAction from Cascade
constraints: table =>
{
table.PrimaryKey("PK_table1", x => x.Id);
table.ForeignKey(
name: "FK_table1_table2_table2Id",
column: x => x.table2Id,
principalTable: "table2",
principalColumn: "Id",
onDelete: ReferentialAction.NoAction);
});

Insert statement conflicts with FK constraint on ApplicationUsers

I've got an Entity as follows:
public class EntityX {
public int Id { get; set; }
...
[ForeignKey("Scheduled By")]
public string ScheduledById { get; set; }
public virtual ApplicationUser ScheduledBy { get; set; }
}
When I try to insert a value into the table, I get the following error:
"The INSERT statement conflicted with the FOREIGN KEY constraint
"FK_dbo.EntityX_dbo.ApplicationUsers_ScheduledById". The conflict
occurred in database "DB", table "dbo.ApplicationUsers", column 'Id'.
The statement has been terminated."
The first thing that comes to mind is that the ApplicationUser table is empty because the IdentityUser table (AspNetUsers) holds all the values. However, its TPH and has a Discriminator column populated with the ApplicationUser table name.
I've verified that the correct Id is being populated when sent in the DB (i.e. it corresponds to an actual User ID) but can't figure out why this is happening.
Thank you in advance. Cheers!
UPDATE:
The space in "Scheduled By" was a typo. It was copied over incorrectly. The actual code has it written as pointed out "ScheduledBy".
UPDATE 2:
The problem it seems lies in the contexts somewhere. I've got two, one DataContext that extends from DbContext as follows:
public class DataContext : DbContext
{
public DbSet<EntityX> EntityXs { get; set; }
...
}
static DataContext()
{
Database.SetInitializer<DataContext> (new CreateInitializer ());
}
public DataContext()
: base("DataContext")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<IdentityUserLogin>().HasKey<string>(l => l.UserId);
modelBuilder.Entity<IdentityRole>().HasKey<string>(r => r.Id);
modelBuilder.Entity<IdentityUserRole>().HasKey(r => new { r.RoleId, r.UserId });
...
}
And another, extending from IdentityDbContext as follows:
public class SecurityContext : IdentityDbContext<ApplicationUser>
{
static SecurityContext()
{
Database.SetInitializer<SecurityContext> (new CreateInitializer ());
}
public SecurityContext()
: base("SecurityContext")
{
Database.Initialize(force: true);
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<IdentityUser>()
.ToTable("AspNetUsers");
modelBuilder.Entity<ApplicationUser>()
.ToTable("AspNetUsers");
modelBuilder.Entity<IdentityUserLogin>().HasKey<string>(l => l.UserId);
modelBuilder.Entity<IdentityRole>().HasKey<string>(r => r.Id);
modelBuilder.Entity<IdentityUserRole>().HasKey(r => new { r.RoleId, r.UserId });
base.OnModelCreating(modelBuilder);
}
With this, the configuration works... but I'm presented with an issue where I've got an extra IdentityRole_Id appearing in the AspNetUserRoles table as described at this post: EF Code First Migration unwanted column IdentityRole_Id. To work around that issue, I followed Hao Kung's advice here: Create ASP.NET Identity tables using SQL script and changed my contexts' OnModelCreating methods this way:
DataContext:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//base.OnModelCreating(modelBuilder);
modelBuilder.Entity<IdentityUserLogin>().HasKey<string>(l => l.UserId);
modelBuilder.Entity<IdentityRole>().HasKey<string>(r => r.Id);
modelBuilder.Entity<IdentityUserRole>().HasKey(r => new { r.RoleId, r.UserId });
}
And SecurityContext...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
var user = modelBuilder.Entity<IdentityUser>()
.ToTable("AspNetUsers");
user.HasMany(u => u.Roles).WithRequired().HasForeignKey(ur => ur.UserId);
user.HasMany(u => u.Claims).WithRequired().HasForeignKey(uc => uc.UserId);
user.HasMany(u => u.Logins).WithRequired().HasForeignKey(ul => ul.UserId);
user.Property(u => u.UserName).IsRequired();
modelBuilder.Entity<ApplicationUser>().ToTable("AspNetUsers"); //Needed?
modelBuilder.Entity<IdentityUserRole>()
.HasKey(r => new { r.UserId, r.RoleId })
.ToTable("AspNetUserRoles");
modelBuilder.Entity<IdentityUserLogin>()
.HasKey(l => new { l.UserId, l.LoginProvider, l.ProviderKey })
.ToTable("AspNetUserLogins");
modelBuilder.Entity<IdentityUserClaim>()
.ToTable("AspNetUserClaims");
var role = modelBuilder.Entity<IdentityRole>()
.ToTable("AspNetRoles");
role.Property(r => r.Name).IsRequired();
role.HasMany(r => r.Users).WithRequired().HasForeignKey(ur => ur.RoleId);
}
Although doing this builds the DB correctly, with a Discriminator column in the AspNetUsers table populating with "ApplicationUser" as the value and without the extra columns in AspNetUserRoles, any attempt at inserting the user's Id value into EntityX as FK fails.
I'm completely lost.
So, it turns out that there wasn't any problem with how the entity was set up. It was due to some issue that was arising when migrating to the same DB via the two contexts. Merging them into one fixed the issue. I've posted how I resolved things below. Hopefully this saves someone else time and torment.
public class SecurityContextContext : IdentityDbContext<ApplicationUser>
{
public DbSet<EntityX> EntityX { get; set; }
...
static SecurityContext()
{
Database.SetInitializer<SecurityContext> (new CreateInitializer());
}
public SecurityContext()
: base("SecurityContext")
{
Database.Initialize(force: true);
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
var user = modelBuilder.Entity<IdentityUser>()
.ToTable("AspNetUsers");
user.HasMany(u => u.Roles).WithRequired().HasForeignKey(ur => ur.UserId);
user.HasMany(u => u.Claims).WithRequired().HasForeignKey(uc => uc.UserId);
user.HasMany(u => u.Logins).WithRequired().HasForeignKey(ul => ul.UserId);
user.Property(u => u.UserName).IsRequired();
user.HasKey(u => u.Id);
var appUser = modelBuilder.Entity<ApplicationUser>().ToTable("AspNetUsers"); //Needed?
appUser.HasMany(u => u.Roles).WithRequired().HasForeignKey(ur => ur.UserId);
appUser.HasMany(u => u.Claims).WithRequired().HasForeignKey(uc => uc.UserId);
appUser.HasMany(u => u.Logins).WithRequired().HasForeignKey(ul => ul.UserId);
appUser.Property(u => u.UserName).IsRequired();
modelBuilder.Entity<IdentityUserRole>()
.HasKey(r => new { r.UserId, r.RoleId })
.ToTable("AspNetUserRoles");
modelBuilder.Entity<IdentityUserLogin>()
.HasKey(l => new { l.UserId, l.LoginProvider, l.ProviderKey })
.ToTable("AspNetUserLogins");
modelBuilder.Entity<IdentityUserClaim>()
.ToTable("AspNetUserClaims");
var role = modelBuilder.Entity<IdentityRole>()
.ToTable("AspNetRoles");
role.Property(r => r.Name).IsRequired();
role.HasMany(r => r.Users).WithRequired().HasForeignKey(ur => ur.RoleId);
}
This configuration works for me. Although the ApplicationUser table does not generate via this mapping, there is still a Discriminator column created in the AspNetUsers table filled with "ApplicationUser". The AspNetUsers table also gets the extra fields that I defined in the ApplicationUser class. The IdentityRole_Id is eliminated and I'm able to assign roles and get them successfully. The FK issue is also resolved. Everything works as intended.
As the error message indicates, your foreign key needs to be associated with a valid entity property. If you place the ForeignKey attribute on a foreign key property the string parameter represents the name of the associated navigation property. Remove the whitespace to match the name of the navegation property:
public class EntityX
{
public int Id { get; set; }
...
[ForeignKey("ScheduledBy")]
public string ScheduledById { get; set; }
public virtual ApplicationUser ScheduledBy { get; set; }
}
use this:
public class EntityX
{
public int Id { get; set; }
[ForeignKey("ScheduledBy")]
public string ScheduledById { get; set; }
[ForeignKey("ScheduledById")]
[InverseProperty("EntityX_1")]
public virtual ApplicationUser ScheduledBy{ get; set; }
}
public class ApplicationUser
{
public string ScheduledById { get; set; }
.
.
.
[InverseProperty("ScheduledBy")]
public virtual ICollection<EntityX> EntityX_1{ get; set; }
}

Resources