Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot create a relationship when using two FK

I'm using EF in my ASP.Net Core application and I'm trying to associate an UserNotification table to my User table. These are the tables structure:

public class User : IdentityUser
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public virtual UserNotifications { get; set; }
}

public class UserNotifications
{
    public int Id { get; set; }

    [Key, ForeignKey("User")]
    public string UserId { get; set; }
    public User User { get; set; }

    [Key, ForeignKey("Sender")]
    public string SenderId { get; set; }
    public virtual User Sender { get; set; }      

    public string Title { get; set; }
    public string Message { get; set; }
}

What I did is create a ForeignKey of UserNotifications which I'm going to store all the notifications that the User has reiceved.

Inside the table UserNotifications I created two FK for User and Sender. Essentially I want store the Id of the User that has reiceved the notification, and the Id of the User that has sent the notification (Sender).

Inside the OnModelCreating I also defined the following logic:

builder.Entity<UserNotifications>(entity =>
{
    entity.HasKey(n => n.Id);
    entity.HasOne(u => u.User)
          .WithOne(u => u.UserNotifications)
          .HasForeignKey<User>(u => u.Id);

    entity.HasOne(u => u.Sender)
          .WithOne(u => u.UserNotifications)
          .HasForeignKey<User>(u => u.Id);
 });

When I type the following building in the console:

add-migration InitialMigration -context MyAppContext

I get:

Cannot create a relationship between 'User.UserNotifications' and 'UserNotifications.Sender', because there already is a relationship between 'UserNotifications.User' and 'User.UserNotifications'. Navigation properties can only participate in a single relationship.

I'm a newbie of EntityFramework so I don't know how to fix this, someone could explain what I did wrong?

Thanks in advance for any help.

like image 777
Rockj Avatar asked Dec 18 '22 20:12

Rockj


1 Answers

The model you are describing represents two one-to-many relationships between the User and UserNotifications (btw, the entity should be named UserNotification) entities. Each EF relationship can be mapped to 0 or 1 unique navigation properties at each side.

You already have two User and Sender reference navigation properties (and corresponding FKs) in UserNotifications. What you need is two corresponding collection navigation properties in User:

public class User : IdentityUser
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public virtual ICollection<UserNotifications> ReceivedNotifications { get; set; }
    public virtual ICollection<UserNotifications> SentNotifications { get; set; }
}

and map the with fluent API:

builder.Entity<UserNotifications>(entity =>
{
    entity.HasKey(n => n.Id);

    entity.HasOne(n => u.User)
        .WithMany(u => u.ReceivedNotifications)
        .HasForeignKey(n => u.UserId)
        .IsRequired()
        .OnDelete(DeleteBehavior.Cascade);

    entity.HasOne(n => n.Sender)
        .WithMany(u => u.SentNotifications)
        .HasForeignKey(n => n.SenderId)
        .IsRequired()
        .OnDelete(DeleteBehavior.Restrict);
 });

Note that since such model introduces the so called multiple cascade paths, you need to turn at least one of the cascade delete off and handle it manually.

like image 123
Ivan Stoev Avatar answered Dec 22 '22 01:12

Ivan Stoev