0
votes

I have read many threads about mapping User and Friends but I have not been able to find a good answer. What I want is that an ApplicationUser should be able to have zero to many friend requests and later zero to many friends.

As you can see in the model FriendRequest has two ApplicationUsers, both User and FutureFriend and this is what's causing problems.

public class ApplicationUser : IdentityUser<int, CustomUserLogin, CustomUserRole,CustomUserClaim>
{
    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser, int> manager, string authenticationType)
    {
CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);
        // Add custom user claims here
        return userIdentity;
    }

    public ApplicationUser()
    {
    }

    [Required]
    public string Alias { get; set; }

    public virtual ICollection<FriendRequest> FriendRequests { get; set; }
}

public class FriendRequest
{
    public int UserId { get; set; }
    public int FutureFriendId { get; set; }
    public virtual ApplicationUser User { get; set; }
    public virtual ApplicationUser FutureFriend { get; set; }
    public DateTime? RequestTime { get; set; }
}

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    modelBuilder.Entity<ApplicationUser>()
    .HasMany(u => u.FriendRequests)
    .WithRequired(f => f.User)
    .HasForeignKey(f => f.UserId);

    modelBuilder.Entity<FriendRequest>()
    .HasKey(f => new { f.UserId, f.FutureFriendId });

    modelBuilder.Entity<FriendRequest>()
    .HasRequired(f => f.FutureFriend)
    .WithMany()
    .HasForeignKey(f => f.FutureFriendId);

    //Did not work either
    //modelBuilder.Entity<FriendRequest>().HasKey(f => new { UserId = f.UserId, FutureFriendId = f.FutureFriendId });
    //modelBuilder.Entity<FriendRequest>()
    //  .HasRequired(f => f.User)
    //  .WithMany()
    //  .HasForeignKey(f => f.UserId);
    //modelBuilder.Entity<FriendRequest>()
    //    .HasRequired(f => f.FutureFriend)
    //    .WithMany()
    //    .HasForeignKey(f => f.FutureFriendId)
    //    .WillCascadeOnDelete(false);
}

Error when trying to create the database:

Introducing FOREIGN KEY constraint 'FK_dbo.FriendRequests_dbo.AspNetUsers_UserId' on table 'FriendRequests' 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.

Update:

Decided to remodel the class, final solution can be found here: SO

1
Add .WillCascadeOnDelete(false) after one of the .HasForeignKey(..) calls.Ivan Stoev
@IvanStoev Thank you! This worked, added .WillCascadeOnDelet‌​e(false) on both .HasForeignKey(..)Ogglas

1 Answers

1
votes

Thank you @IvanStoev!

One solution in my model is by disabling .WillCascadeOnDelet‌​e(false) on one or both of the .HasForeignKey(..). Since CASCADE causes corresponding rows to be deleted from the referencing table if that row is deleted from the parent table... and I'm a little paranoid.

I decided to disable the CascadeDeleteConvention on both one to many relations and many to many releations instead.

My solution:

modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();

Possible solution:

modelBuilder.Entity<ApplicationUser>()
    .HasMany(u => u.FriendRequests)
    .WithRequired(f => f.User)
    .HasForeignKey(f => f.UserId)
    .WillCascadeOnDelete(false);

modelBuilder.Entity<FriendRequest>()
    .HasKey(f => new { f.UserId, f.FutureFriendId });

modelBuilder.Entity<FriendRequest>()
    .HasRequired(f => f.FutureFriend)
    .WithMany()
    .HasForeignKey(f => f.FutureFriendId)
    .WillCascadeOnDelete(false);