Faraji Anderson
Faraji Anderson

Reputation: 661

Entity Framework define complex object relationship

I have a User and Following class defined as such:

public class User : IdentityUser
{
    public User()
    {
        Followers = new HashSet<Following>();
        Following = new HashSet<Following>();
    }

    [Key]
    public string ID { get; set; }
...
...

    public virtual ICollection<Following> Followers { get; set; }

    public virtual ICollection<Following> Following { get; set; } 
}

public class Following
{
        [Key]        
        public int ID {get;set;}

        [MaxLength(100)]
        public string follower { get; set; }

        [MaxLength(100)]
        public string following { get; set; }           

        public virtual User UserFollower { get; set; }

        public virtual User UserFollowing { get; set; }
 }

The properties follower and following in Following are both foreign keys for the User object and represent the relationship. Then in the DBcontext class I'm overriding the OnModelCreating:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {      
        modelBuilder.Entity<User>()
            .HasMany<Following>(u => u.Followers)
            .WithOptional()
            .HasForeignKey(c => c.following);

        modelBuilder.Entity<User>()
            .HasMany<Following>(u => u.Following)
            .WithOptional()
            .HasForeignKey(c => c.follower);
}

This works perfectly for getting a user's followers and following:

User user = await UserManager.FindByIdAsync(ID);
List<Following> followers = user.Following.ToList();

My question in basic is how do I create the UserFollower & UserFollowing relationship so that each of these properties of Following is mapped to a User?

Ideally I'd be able to do something along the lines of:

User user = await UserManager.FindByIdAsync(ID);
List<Following> followers = user.Following.ToList();

User userFollowing = followers[0].UserFollowing;

Upvotes: 1

Views: 480

Answers (1)

Adnan Umer
Adnan Umer

Reputation: 3689

Modify your model a little bit

public class User : IdentityUser
{
    public User()
    {
        // Don't do this. Entity Framwork will do that for you
        // Followers = new HashSet<Following>();
        // Following = new HashSet<Following>();
    }

    // Don't add this. IdentityUser has already defined it as `Id`
    // [Key]
    // public string ID { get; set; }

    public virtual ICollection<Following> Followers { get; set; }

    public virtual ICollection<Following> Following { get; set; } 
}

public class Following
{
    [Key]        
    public int ID {get;set;}

    // [MaxLength(100)] No need to do this as this is Foreign Key Property
    public string follower { get; set; }

    // [MaxLength(100)] No need to do this as this is Foreign Key Property
    public string following { get; set; }           

    public virtual User UserFollower { get; set; }

    public virtual User UserFollowing { get; set; }
}

And then user fluent APIs to define relationship

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{      
    modelBuilder.Entity<User>()
        .HasMany(u => u.Followers)
        .WithRequired(f => f.UserFollower)
        .HasForeignKey(c => c.following);

    modelBuilder.Entity<User>()
        .HasMany(u => u.Following)
        .WithRequired(f => f.UserFollowing)
        .HasForeignKey(c => c.follower);
}

This will create a bi-directional relationship. Further EntityFramework will override all virtual properties and define behavior that you are expecting.

If you haven't modified EntityFramework configuration you will be able to do this directly

User user = await UserManager.FindByIdAsync(ID);
List<Following> followers = user.Following.ToList();

User userFollowing = followers[0].UserFollowing;

Upvotes: 1

Related Questions