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
@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
};
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
};