How do I implement self-regulation from many to many relationships with Entity Framework Core 1.1?

I am following this guide to implement my friendship system with EF Core 1.1: http://www.codedodle.com/2014/12/social-network-friends-database.html

Friendship.cs

public class Friendship
{
    public Guid ApplicationUserId { get; set; }
    public ApplicationUser ApplicationUser { get; set; }

    public Guid FriendId { get; set; }
    public ApplicationUser Friend { get; set; }

    public StatusCode Status { get; set; }

    public Guid ActionUserId { get; set; }
    public ApplicationUser ActionUser { get; set; }

    public byte[] Timestamp { get; set; }
}

public enum StatusCode
{
    Pending = 0,
    Accepted = 1,
    Declined = 2,
    Blocked = 3
}

      

ApplicationUser.cs

public class ApplicationUser : IdentityUser<Guid>
{
    ...

    public ICollection<Friendship> FriendRequestsMade { get; set; }

    public ICollection<Friendship> FriendRequestsAccepted { get; set; }

    public byte[] Timestamp { get; set; }
}

      

MyDbContext.cs

public class SocialCircleContext : IdentityDbContext<ApplicationUser, Role, Guid>
{

     builder.Entity<Friendship>()
        .HasIndex(x => new { x.ApplicationUserId, x.FriendId })
        .IsUnique();

     builder.Entity<Friendship>()
        .HasOne(x => x.ApplicationUser)
        .WithMany(y => y.FriendRequestsMade)
        .HasForeignKey(x => x.ApplicationUserId).OnDelete(DeleteBehavior.Restrict);

    builder.Entity<Friendship>()
        .HasOne(x => x.Friend)
        .WithMany(y => y.FriendRequestsAccepted)
        .HasForeignKey(x => x.FriendId);         
}

      

AddMigration InitialMigration Result

The relationship represented by the "Friendship.ActionUser" navigation property of type "ApplicationUser" cannot be defined. Either manually set up the relationship, or ignore this property from the model.

Also, since EF Core is fast, I found many different ways to do this. I'm not sure about my implementation of many-to-many relationships, can anyone give me some advice?

  • How can I determine the relationship between Friendship.ActionUser and ApplicationUser?
  • Any advice on what is the correct way to implement this self-regulation between many-to-many relationships? EF Core is fast, I found many different ways on the internet, but they seem outdated.

Thank!:)

+3


source to share


1 answer


Ideally, when the ambiguity in finding the relationship is resolved, EF should create the rest of the relationship by convention, but this does not happen due to an error. (Filed Error )

Your model classes are correct for what you are trying to do. In order for EF to successfully build the model, there are a few missing pieces left.

First, resolve the exception you are seeing. Your class ApplicationUser

has 2 collectible navigations pointing to Friendship

. And the class Friendship

has 3 navigation pointers pointing ApplicationUser

. While EF Core does a great job of creating relationships by convention, in this case it doesn't know how to create navigation pairs with back navigation. So user input is needed with annotations / fluent API. In your case, you are creating 2 relationships using a fluent API that uses up to 2 navs on each side. This leaves us with only navigationFriendship.ActionUser

without any relationship. At the moment, EF Core has no confusion about how to create relationships from it, but due to a bug, it doesn't. This means that you need to set up these relationships manually using the fluent API.

builder.Entity<Friendship>().HasOne(e => e.ActionUser).WithOne().HasForeignKey<Friendship>(e => e.ActionUserId);

      

This will create a one-to-one relationship. You can use HasOne(...).WithMany()

to create one-to-many relationship.



This will lead you to the error above. Now you will see another error as the class Friendship

does not have a specific primary key. Although the article says to create a unique index, but for a many-to-many join table, the join table is configured with a composite PK so that it can represent a unique join. Therefore, instead of calling HasIndex

as above, you should use the following code.

builder.Entity<Friendship>().HasKey(e => new { e.ApplicationUserId, e.FriendId });

      

After the above code, you can remove the call HasIndex

because PKs are always unique and most databases have an index defined for PK.

With the above changes, your model should work well.

Other: Since the relationship defined Friendship.ActionUser

is somewhat ambiguous for it to be one-to-one or one-to-many, perhaps it shouldn't be a relationship at all. ActionUserId must be one of the values ApplicationUserId

or FriendId

, you can easily access ActionUser by choosing one of these navigation. You can do ActionUser [NotMapped]

in EF and computed with a return value ApplicationUser/Friend

based on ActionUserId

. It's a design choice though. There is no right or wrong way. Whatever the meaning and helps you the most in how you consume it, it should be used.

+1


source







All Articles