1
votes

I'm trying to recreat a followers/followees system with Code First in ASP.NET. I can't find the right way to implement this (MVC pattern). There's my "User" class :

public class User
{
    public User()
    {
        this.Followers = new HashSet<User>();
        this.Follows = new HashSet<User>();
    }
    
    [Key]
    public int UserId { get; set; }
    public string Mail { get; set; }
    public string Password { get; set; }
    public string LastName { get; set; }
    public string FirstName { get; set; }
    public string Locality { get; set; }
    public string PhoneNumber { get; set; }
    public string Description { get; set; }
    public string ProfileImage { get; set; }

    public virtual ICollection<User> Followers { get; set; }
    public virtual ICollection<User> Follows { get; set; }
}

I have been able to create the database with the join table named "Subscriptions" with this dbcontext class :

public FakebookDBContext()
        : base("name=FakebookDBContext")
    {
    }

    public DbSet<User> Users { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {

        modelBuilder.Entity<User>()
                    .HasMany<User>(fer => fer.Follows)
                    .WithMany(fow => fow.Followers)
                    .Map(ff =>
                    {
                        ff.MapLeftKey("UserFollowerId");
                        ff.MapRightKey("UserFollowedId");
                        ff.ToTable("Subscription");
                    });

    }

While testing the Api related to my "User" class (generated automatically), i noticed two things :

  1. While sending a POST request to my API with a User who follows an already existing User, it creates me two new User to the Database (the Subscription table is correclty filled tho)

  2. While sending a PUT request to my API trying to change an already existing user Follows, the "Subscription" table remains unchanged.

Example for POST :

Input :

{
"$id" : 1,
    "Followers": [
        {
            "$id": "2",
            "Followers": [],
            "Follows": [{"$ref": "1"}],
            "UserId": 1,
            "Mail": null,
            "Password": null,
            "LastName": null,
            "FirstName": null,
            "Locality": null,
            "PhoneNumber": null,
            "Description": null,
            "ProfileImage": null
        }
    ],
    "Follows": [],
    "Mail": null,
    "Password": null,
    "LastName": null,
    "FirstName": null,
    "Locality": null,
    "PhoneNumber": null,
    "Description": null,
    "ProfileImage": null
}

Output :

{
"$id": "1",
"UserId": 24,
"Mail": null,
"Password": null,
"LastName": null,
"FirstName": null,
"Locality": null,
"PhoneNumber": null,
"Description": null,
"ProfileImage": null,
"Followers": [
    {
        "$id": "2",
        "UserId": 25,
        "Mail": null,
        "Password": null,
        "LastName": null,
        "FirstName": null,
        "Locality": null,
        "PhoneNumber": null,
        "Description": null,
        "ProfileImage": null,
        "Followers": [],
        "Follows": [
            {
                "$ref": "1"
            }
        ]
    }
],
"Follows": []

}

I concluded that i didn't achieve to link Users together correctly. It doesn't seem references to existing users are found and the framework(?) just creates new objects.

I would like to avoid to make a "Subscription" class and keep the User model that way (if possible). I'm quite new in IT so feel free to give any advice on how i should implement this better. Thank you !

1
It might be because of a missing "ForeignKey" attribute on UserId but i don't really know how to make it work.Teodor Daue
Many-Many joins require a new table to sit in the middle.Jeremy Lakeman
Thanks for your answer, but as said in my question, i managed to create this join table called "Subscription" (see second code snippet)Teodor Daue
You haven't posted any code from your save method. You need to ensure that you reload or attach existing User instances with their PK values.Jeremy Lakeman

1 Answers

0
votes

I think the easiest way would be to create two other classes. One for followers and one for following. Each class would have one User and one ICollection<User>

I know you wanted to avoid making new classes but this is the simplest way to tell EF what you want to do.