C# Model User, Friend Requests and Friends with Entity Framework Code First

c# ef-code-first entity-framework entity-framework-6

Question

I have previously asked a question here on SO about a similar topic but have since taken a different approach. This is my model:

public class ApplicationUser : IdentityUser<int, CustomUserLogin, CustomUserRole,CustomUserClaim>
{   
    public ApplicationUser()
    {
        Friends = new List<Friend>();
    }

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

    public virtual ICollection<Friend> Friends { get; set; }
}

public class Friend
{
    public virtual int Id { get; set; }

    public virtual ApplicationUser RequestedBy { get; set; }

    public virtual ApplicationUser RequestedTo { get; set; }

    public DateTime? RequestTime { get; set; }

    public FriendRequestFlag FriendRequestFlag { get; set; }
}

public enum FriendRequestFlag
{
    None,
    Approved,
    Rejected,
    Blocked,
    Spam
};

I can add Friends with this approach and they populate when I get them from database, sample:

public void AddFriendRequest(ApplicationUser user, ApplicationUser friendUser)
{
    var friendRequest = new Friend()
    {
        RequestedBy = user,
        RequestedTo = friendUser,
        RequestTime = DateTime.Now,
        FriendRequestFlag = FriendRequestFlag.None
    };

    user.Friends.Add(friendRequest);
}

When I run the code above, the friend table in the database looks like this after execution:

SQL

When I get a user I would wan't Entity Framework to get all rows in Friend were the user is either RequestedBy or RequestedTo. Is this possible to do with EF? For example with Fluent API? I would also like to map the keys so that [ApplicationUser_Id] is not needed.

1
1
8/17/2016 2:23:43 PM

Accepted Answer

@Mukesh thanks for your answer but I decided to take another approach since your solution did not get all rows in Friend were the user is either RequestedBy or RequestedTo. This is my solution:

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

    public ApplicationUser()
    {
        SentFriendRequests = new List<Friend>();
        ReceievedFriendRequests = new List<Friend>();
    }

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

    public string Name { get; set; }

    public byte[] ProfilePicture { get; set; }

    public virtual ICollection<Friend> SentFriendRequests { get; set; }

    public virtual ICollection<Friend> ReceievedFriendRequests { get; set; }

    [NotMapped]
    public virtual ICollection<Friend> Friends {
        get
        {
            var friends = SentFriendRequests.Where(x => x.Approved).ToList();
            friends.AddRange(ReceievedFriendRequests.Where(x => x.Approved));
            return friends;
        } }
}

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

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

    modelBuilder.Entity<Friend>()
        .HasRequired(a => a.RequestedBy)
        .WithMany(b => b.SentFriendRequests)
        .HasForeignKey(c => c.RequestedById);

    modelBuilder.Entity<Friend>()
        .HasRequired(a => a.RequestedTo)
        .WithMany(b => b.ReceievedFriendRequests)
        .HasForeignKey(c => c.RequestedToId);
}

public class Friend
{
    [Key, Column(Order = 0)]
    public int RequestedById { get; set; } 
    [Key, Column(Order = 1)]
    public int RequestedToId { get; set; } 
    public virtual ApplicationUser RequestedBy { get; set; }
    public virtual ApplicationUser RequestedTo { get; set; }

    public DateTime? RequestTime { get; set; }

    public DateTime? BecameFriendsTime { get; set; }

    public FriendRequestFlag FriendRequestFlag { get; set; }

    [NotMapped]
    public bool Approved => FriendRequestFlag == FriendRequestFlag.Approved;

    public void AddFriendRequest(ApplicationUser user, ApplicationUser friendUser)
    {
        var friendRequest = new Friend()
        {
            RequestedBy = user,
            RequestedTo = friendUser,
            RequestTime = DateTime.Now,
            FriendRequestFlag = FriendRequestFlag.None
        };
        user.SentFriendRequests.Add(friendRequest);
    }
}

public enum FriendRequestFlag
{
    None,
    Approved,
    Rejected,
    Blocked,
    Spam
};
4
8/19/2016 5:57:28 AM

Popular Answer

When I get a user I would wan't Entity Framework to get all rows in Friend were the user is either RequestedBy or RequestedTo. Is this possible to do with EF?

Yes you can absolutely do that, just you need to disable lazy loading feature by setting false value to LazyLoadingEnabled,

context.Configuration.LazyLoadingEnabled = false;

If you want to fetch friends as well in above scenario then you can get friend list by including navigation property.

context.User.Include(x => x.Friends).ToList();

I would also like to map the keys so that [ApplicationUser_Id] is not needed.

To achienve this need to use ForeignKey attribute so that it will not generate [Application_Id] column in table, Please follow below updated model of yours.

public class ApplicationUser
    {
        [Key]
        public virtual int Id { get; set; }
        public ApplicationUser()
        {
            Friends = new List<Friend>();
        }
        [Required]
        public string Alias { get; set; }

        [ForeignKey("RequestedBy_Id")]
        public virtual ICollection<Friend> Friends { get; set; }
    }

    public class Friend
    {
        public virtual int Id { get; set; }

        [ForeignKey("RequestedBy")]
        public virtual int RequestedBy_Id { get; set; }
        public virtual ApplicationUser RequestedBy { get; set; }

        public virtual ApplicationUser RequestedTo { get; set; }

        public DateTime? RequestTime { get; set; }

        public FriendRequestFlag FriendRequestFlag { get; set; }
    }

    public enum FriendRequestFlag
    {
        None,
        Approved,
        Rejected,
        Blocked,
        Spam
    };


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow