1110
1110

Reputation: 6829

How to map double related objects in entity framework, i.e. defining two FKs between the same entities

I have table User and one more table ProfileView.
They are in one to many relation.
I have a problem to create a reference between those tables via code first.
PageView looks like this:

public class ProfileView
    {
        public int ProfileViewId { get; set; }
        public int ViewedWho { get; set; }
        public virtual ApplicationUser ViewedWhoUser { get; set; }
        public DateTime ViewDate{get;set;}
        public int ViewedBy { get; set; }
        public virtual ApplicationUser ViewedByUser { get; set; }
    }

As you can see there are two references from User to ProfileView how can I map this objects?
Right now EF auto gerate some keys with underscore not the one I created in boject.

Additionaly when I creating related object do I actually need to have something like ICollection<ProfileView> ... in related User object?
I have tried to map it like this:

modelBuilder.Entity<ApplicationUser>()
                .HasMany(m => m.WhoViewedMyProfile)
                .WithMany(m => m.WhosProfileIViewed)
                .Map(x => x.MapLeftKey("UserId")
                    .MapRightKey("ViewedWho")
                    .ToTable("ViewedBy"));

But all I get is this:
enter image description here
ApplicationUser.cs has:

public ICollection<ApplicationUser> WhoViewedMyProfile { get; set; }
        public ICollection<ApplicationUser> WhosProfileIViewed { get; set; }

Upvotes: 3

Views: 807

Answers (1)

JotaBe
JotaBe

Reputation: 39014

There are three ways to do it:

  1. using attributes
  2. using Fluent API
  3. using conventions (not for this case)

NOTE: repeat for both properties

With attributes, you simply have to add ForeignKey attribute like this:

[ForeignKey("ViewedWho")]
public virtual ApplicationUser ViewedWhoUser { get; set; }

With Fluent API, you need to configure it like this: override the OnModelCreating(DbModelBuilder builder) method, and configure the relation like this:

  modelBuilder.Entity<ProfileView>
    .HasRequired(pv => pv.ViewedWhoUser) // or HasOptional
    .WithMany()
    .HasForeingKey(pv => pv.ViewedWho);

This works when there is only one realtion, but for more than one, you need to use one of the previous techniques: See the end of the Relationship Convention section of Code First Conventions

With conventions, you have to follow a convention that EF understands. I'm not absolutely sure, but try naming the ForeignKey properties like the navigation property with Id appended at the end, i.e.

public int ViewedWhoUserId { get; set; }

NOTE: in fact, the EDM is constructed from a combination of the three techniques, so you can rely partially on conventions, for example for PKs, and on attributes or the Fluent API, for "fine-tuning" the model. But, as in this case, there are several differences on what you can do with the different techniques. Interestingly, on EF 6.1 you can create your own custom conventions which can spare you writing some attributes and Fluent API configuraions.

Upvotes: 2

Related Questions