Sameed
Sameed

Reputation: 703

How to create a third table for Many to Many relationship in Entity Framework Core?

I have two classes: One is User

 public class User
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Email { get; set; }
        public List<Subscription> Subscriptions { get; set; }
    }

Other is Subscription:

public class Subscription
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public decimal Price { get; set; }
    }

As you can see that User has a list of Subscriptions. Now when using the entity framework code first approach I am getting a table for User which doesn't contain Subscriptions but a new column for User Id is being added to Subscription table. I was expecting to have a third table which contains two columns one with User ID and the other with subscription ID. How can I achieve this?

Upvotes: 4

Views: 2430

Answers (2)

Alexan
Alexan

Reputation: 8637

From documentation:

Many-to-many relationships without an entity class to represent the join table are not yet supported. However, you can represent a many-to-many relationship by including an entity class for the join table and mapping two separate one-to-many relationships.

So this answer is correct.

I just corrected code a little bit:

class MyContext : DbContext
{
    public DbSet<Use> Users { get; set; }
    public DbSet<Subscription> Subscriptions { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<UserSubscription>()
            .HasKey(t => new { t.UserId, t.SubscriptionId });

        modelBuilder.Entity<UserSubscription>()
            .HasOne(pt => pt.User)
            .WithMany(p => p.UserSubscription)
            .HasForeignKey(pt => pt.UserId);

        modelBuilder.Entity<UserSubscription>()
            .HasOne(pt => pt.Subscription)
            .WithMany(t => t.UserSubscription)
            .HasForeignKey(pt => pt.SubscriptionId);
    }
}

public class User
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Email { get; set; }
        public List<UserSubscription> UserSubscriptions{ get; set; }
    }

public class Subscription
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public decimal Price { get; set; }
        public List<UserSubscription> UserSubscriptions{ get; set; }
    }

public class UserSubscription
{
    public int UserId { get; set; }
    public User User { get; set; }

    public int SubscriptionId { get; set; }
    public Subscription Subscription { get; set; }
}

PS. You don't need use virtual in navigation property, because lazy loading still not available in EF Core.

Upvotes: 3

Ramy M. Mousa
Ramy M. Mousa

Reputation: 5943

Create a third middle table named: UserSubscriptions for example.

public class User
    {
        public int ID { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Email { get; set; }
        public virtual ICollection<UserSubscription> Subscriptions { get; set; }
    }


public class Subscription
{
    public int ID { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}

  public class UserSubscription
{
    public int ID { get; set; }
    public int SubscriptionID { get; set; }
    public decimal Price { get; set; }
    public int UserID { get; set; }
    public virtual User { get; set; }
    public DateTime BeginDate { get; set; }
    public DateTime EndDate { get; set; }
}

Second Solution:

Add reference for Subscription to User and name it CurrentSubscription for example.

public class User
    {
        public int ID { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Email { get; set; }
        public int CurrentSubscriptionID { get; set; }
        public virtual Subscription Subscription { get; set; }
    }


public class Subscription
{
    public int ID { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}

Upvotes: 1

Related Questions