EF FOREIGN KEY constraint may cause cycles or multiple cascade paths - c#

I am developing a sample application where people can place bets on sports events and earn points. It has the following Entity Framework Code-First models:
public class Person
{
[Key]
public int Id { get; set; }
[Required]
public string Name { get; set; }
}
public class Race
{
[Key]
public int Id { get; set; }
[Required]
public string Name { get; set; }
}
public class RaceBet
{
[Key]
public int Id { get; set; }
[Required]
public int RaceId { get; set; }
[Required]
public int PersonId { get; set; }
[Required]
public int CompetitorId { get; set; }
public virtual Race Race { get; set; }
public virtual Person Person { get; set; }
public virtual Person Competitor { get; set; }
}
A Person can place a bet for a Race and he can bet on any other Person (Competitor).
The models will produce the following error:
Introducing FOREIGN KEY constraint 'FK_dbo.RaceBets_dbo.People_PersonId' on table 'RaceBets' 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. See previous errors.
I tried removing the OneToManyCascadeDeleteConvention, adding fluent configurations to prevent cascade delete for RaceBet and all other variations of the api, but everything fails.
modelBuilder
.Entity<RaceBet>()
.HasRequired(x => x.Person)
.WithMany()
.HasForeignKey(x => x.PersonId)
.WillCascadeOnDelete(false);
How can I resolve this? Is the concept behind my models wrong?
Thanks!

Thanks to Oleg for his comment:
I can't to reproduce exception with this code: protected override void
OnModelCreating(DbModelBuilder modelBuilder) {
modelBuilder.Conventions.Add(new
System.Data.Entity.ModelConfiguration.Conventions.OneToManyCascadeDeleteConventi‌​on());
modelBuilder .Entity() .HasRequired(x => x.Person)
.WithMany() .HasForeignKey(x => x.PersonId)
.WillCascadeOnDelete(false); }
This fixed the model creation.

Related

How to have foreign key and related navigation property with non-standard name

In Entity Framework Core (v5.0.6) I'm trying to create a relationship where the object has both a foreign key id field AND a navigation property both of which have non-standard names but when I try to build a migration, I'm getting an error saying Unable to determine the relationship represented by navigation 'Org.IntegrationAdmin' of type 'OrgUser'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'
My code is:
public class OrgUser
{
public Guid Id { get; set; }
public string Name { get; set; }
public Guid OrgId { get; set; }
public virtual Org? Org { get; set; }
}
public class Org
{
[ForeignKey(nameof(OrgUser))]
public Guid IntegrationAdminId { get; set; }
[ForeignKey(nameof(IntegrationAdminId))]
public virtual OrgUser? IntegrationAdmin { get; set; }
}
The reason for the non-standard names is that the Org class will actually have several foreign key / navigation properties in it so using standard naming is not an option.
I would rather do this with attributes rather than fluent syntax.
I want to have both the id and the navigation property as sometimes will want to include the navigation property but others, just want the id, which will be useful for comparing records without the overhead of doing a db join.
Update:
Sorry for wasting peoples time but I made the classic mistake of inadvertently editing out the important part of my code 🤦‍♂️🤦‍♂️🤦‍♂️
I've added the reference to Org into OrgUser that was confusing EF!
Try this
public class OrgUser
{
[Key]
public Guid Id { get; set; }
public string Name { get; set; }
[InverseProperty(nameof(Org.IntegrationAdmin))]
public virtual ICollection<Org> Orgs { get; set; }
}
public class Org
{
[Key]
public Guid Id { get; set; }
public Guid? IntegrationAdminId { get; set; }
[ForeignKey(nameof(IntegrationAdminId))]
[InverseProperty("Orgs")]
public virtual OrgUser IntegrationAdmin { get; set; }
}
or you can try dbcontext
modelBuilder.Entity<Org>(entity =>
{
entity.HasOne(d => d.IntegrationAdmin)
.WithMany(p => p.Orgs)
.HasForeignKey(d => d.IntegrationAdminId )
.OnDelete(DeleteBehavior.ClientSetNull);
});
I've found the problem, it was that in addition to the OrgUser ref in Org, there was also an Org ref in OrgUser that I'd not noticed.
This confused EF and resulted in an error message that pointed at the wrong thing and confused the hell out of me.
I removed all ForeignKey attributes and then added the following to my DbContext
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Org>(entity =>
{
entity.HasOne(o => o.IntegrationAdmin)
.WithMany();
});
modelBuilder.Entity<OrgUser>(entity =>
{
entity.HasOne(d => d.Org)
.WithMany();
});
}

How do I remedy "cycles or multiple cascade paths"?

I have three entities:
ApplicationUser:
public class ApplicationUser : IdentityUser<Guid>
{
// more properties
public List<MeetingNotification> MeetingNotifications { get; set; }
}
MeetingNotifications:
public class MeetingNotification
{
public Guid Id { get; set; }
public Guid MeetingId { get; set; }
public Meeting Meeting { get; set; }
public Guid SummonedUserId { get; set; }
public ApplicationUser SummonedUser { get; set; }
}
Meetings:
public class Meeting
{
public Guid Id { get; set; }
// more properties
public Guid OrganizerId { get; set; }
public ApplicationUser Organizer { get; set; }
public List<MeetingNotification> Notifications { get; set; }
}
The relationships are as such:
One ApplicationUser has many MeetingNotifications
One MeetingNotification has one ApplicationUser and one Meeting
One Meeting has many MeetingNotifications
When I try to update-database, I get the error message
Introducing FOREIGN KEY constraint 'FK_MeetingNotifications_Meetings_MeetingId' on table 'MeetingNotifications' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
This error is my arch nemesis, as I struggle to understand were the error lies. Is it in Meeting or in MeetingNotification. Or somewhere else?
I have tried these three definitions:
modelBuilder.Entity<MeetingNotification>()
.HasOne(m => m.Meeting)
.WithMany(n => n.Notifications)
.HasForeignKey(fk => fk.Id).OnDelete(DeleteBehavior.NoAction);
modelBuilder.Entity<MeetingNotification>()
.HasOne(m => m.Meeting)
.WithMany(n => n.Notifications)
.HasForeignKey(fk => fk.MeetingId).OnDelete(DeleteBehavior.NoAction);
modelBuilder.Entity<Meeting>()
.HasMany(n => n.Notifications)
.WithOne(m => m.Meeting)
.HasForeignKey(fk => fk.MeetingId).OnDelete(DeleteBehavior.NoAction);
... but they don't seem to do anything. It's just the same error message every time
Update
I finally found a way!
modelBuilder.Entity<MeetingNotification>()
.HasOne(m => m.Meeting)
.WithMany(n => n.Notifications)
.OnDelete(DeleteBehavior.Restrict);
... and the error went away! But I don't fully understand why, so any good explanation would be appreciated!

Entity Framework Core - Code First - Two Foreign Keys - One Table

I am using EF Core. I want my base class to keep reference of CreateByUser, and LastModifiedByUser. Unfortunately I can only get it to work with one foreign key. When I try to add a second foreign key I get this error:
Introducing FOREIGN KEY constraint 'FK_Assignments_Users_LastModifiedByUserId' on table 'Assignments' 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. Note that I can use "Add-Migration" with out any errors, but once I run "Update-Database" it errors.
Below is the relevant code to the problem and error.
public abstract class DivBase
{
[Key]
public int Id { get; set; }
[Required]
public DateTimeOffset DateCreated { get; set; }
public int CreatedByUserId { get; set; }
[Required]
public DateTimeOffset LastDateModified { get; set; }
public int LastModifiedByUserId { get; set; }
[ForeignKey("CreatedByUserId")]
public DivUser CreatedByUser { get; set; }
[ForeignKey("LastModifiedByUserId")]
public DivUser LastModifiedByUser { get; set; }
}
public class DivUser
{
[Key]
public int Id { get; set; }
[Required]
[MaxLength(256)]
public string Name { get; set; }
[Required]
[MaxLength(256)]
public string Email { get; set; }
}
public class DivAssignment : DivBase, IDivEvent
{
public DateTimeOffset StartDate { get; set; }
public DateTimeOffset EndDate { get; set; }
}
public interface IDivEvent
{
[Required]
public DateTimeOffset StartDate { get; set; }
[Required]
public DateTimeOffset EndDate { get; set; }
}
Also, If I make one of the properties nullable it will compile, but I fear that will cause problems later.
Apparently you have a 2 Fks to the same table in the same row so imagine if you delete a user who has created an assignment and Modified one what should happen, delete the assignment what if other users modified it this will be nulls in heir tables.
so
You need to specify the CascadeOnDelete to false using FluentApi
In the ApplicationContext:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<DivAssignment>()
.HasRequired(c => c.CreatedByUser)
.WithMany(u => u.CreatedDivAssignments)
.HasForeignKey(c => c.CreatedByUserId)
.WillCascadeOnDelete(false);
modelBuilder.Entity<DivAssignment>()
.HasRequired(c => c.LastModifiedByUser)
.WithMany(u => u.ModifiedDivAssignments)
.HasForeignKey(c => c.LastModifiedByUserId)
.WillCascadeOnDelete(false);
}
Then add-migration then update-database

Self-referencing Entity may cause cycles or multiple cascade paths

I have the following entity:
public class Department
{
public int Id { get; set; }
public string Name { get; set; }
public List<Employee> Employees { get; set; }
public int? HeadDepartmentId { get; set; }
public Department HeadDepartment { get; set; }
public List<Department> ChildDepartments { get; set; }
}
I Add-Migration and then try to update database and as a result:
Introducing FOREIGN KEY constraint 'FK_Departments_Departments_HeadDepartmentId' on table 'Departments' 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.
I try next:
builder.Entity<Department>()
.HasOne(p => p.HeadDepartment)
.WithMany(p => p.ChildDepartments)
.HasForeignKey(p => p.HeadDepartmentId).OnDelete(DeleteBehavior.ClientSetNull);
But it doesnt help.

One to one relation in EntityFramework code first - Set Columnames of relations

i created the below entitie.
[Table("User")]
public class User
{
[...]
[Key]
public String ID { get; set; }
[Column("CreatedBy")]
public virtual User CreatedBy { get; set; }
}
with:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>().HasRequired(a => a.CreatedBy)
.WithRequiredPrincipal();
}
When the tables are created the columname of CreatedBy is "User_ID" although I used the Column attribute. The Columname should be "CreatedBy".
I changed the above code line to
modelBuilder.Entity<User>().HasRequired(a => a.CreatedBy)
.WithRequiredPrincipal().Map(e => e.MapKey("CreatedBy"))
and added in the pakage manager a new migration with add-migration. On Update-Database I get the message: Entities in 'DALDbContext.Users' participate in the 'User_CreatedBy' relationship. 0 related 'User_CreatedBy_Source' were found. 1 'User_CreatedBy_Source' is expected.
My tables are empty. Does someone know a workaround for this?
Not exactly sure what would have lead to your exact issue. However, I would probably just stick to either attribute based configuration or fluent api based configuration. In both cases its best practice to include both the navigation property and foreign key. Moving to this approach is nice and clean and may sort your problem.
Attribute based
public class User
{
[Key]
public string Id { get; set; }
[Column("CreatedBy")]
public int? CreatedByUserId { get; set; }
[ForeignKey("CreatedByUserId")]
public virtual User CreatedBy { get; set; }
}
Fluent api based
public class User
{
public string Id { get; set; }
public int? CreatedByUserId { get; set; }
public virtual User CreatedBy { get; set; }
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// add in configuration for table name, pk, etc
modelBuilder.Entity<User>()
.Property(p => p.CreatedByUserId)
.HasColumnName("CreatedBy");
modelBuilder.Entity<User>()
.HasOptional(x => x.CreatedBy)
.WithMany()
.HasForeignKey(x => x.CreatedByUserId);
}

Categories

Resources