Thomas
Thomas

Reputation: 12647

Entity-Framework 6, defining relationship by two IDs

Context: I have to change a part of a Model from a single value to a List of entries and need help defining the relationship between the two classes.

The Model (simplified) looks like this:

public class Settings {
  public Guid Id { get; set; }

  public Guid NodeId { get; set; }
  public Guid UserId { get; set; }
  public Guid TemplateId { get; set; }

  // plus the respective virtual properties and a few more irrelevant things.
}

Now the relationship has changed so that I have to handle multiple Templates, plus a few new flags, to something like this:

public class Settings {
  public Guid Id { get; set; }
  public Guid NodeId { get; set; }
  public Guid UserId { get; set; }
  public ICollection<TemplateConfig> Configs { get; set; }
  // ...
}

public class TemplateConfig {
  public Guid NodeId { get; set; }
  public Guid UserId { get; set; }
  public Guid TemplateId { get; set; }
  // and a few more flags
}

builder.Entity<TemplateConfig>().HasKey(t => new { t.NodeId, t.UserId, t.TemplateId });

Since many of my access will be directly on this list and based on either all entries for a Node, a User or a Template, I don't mind the redundancy in the IDs, Actually I prefer it.

I'd like to not have to add a SettingsId just to be able to define this relationship, but rather do something like this:

builder.Entity<Settings>()
       .HasMany(s => s.Configs)
       .HasForeignKey(s => new {s.NodeId, s.UserId});

So based on the shared ID-pair NodeId, UserId.

But my EF knowledge is still very limited.

I've tried it through the DbModelBuilder and through ForeignKey and Column-attributes. Different errors; all boiling down to a mismatch in the number of IDs between the Principal and the Dependant in the relationship.

Thank you for any help.

Upvotes: 0

Views: 562

Answers (1)

Giorgi Chkhikvadze
Giorgi Chkhikvadze

Reputation: 694

You Settings class has a single column primary key public Guid Id { get; set; }. when you define relationship, EF core tries to bind 2 column foreign key .HasForeignKey(s => new {s.NodeId, s.UserId}); to 1 column primary key of 'Settings' which is not possible. But you can tell EF to bind a foreign key to different columns which are called "Principal Key". Try adding .WithPrincipal() in your code like this:

 builder.Entity<Settings>()
            .HasMany(s => s.Configs)
            .WithOne()
            .HasForeignKey(c => new {c.NodeId, c.UserId})
            .HasPrincipalKey(s => new {s.NodeId, s.UserId});

Answer for EF 6:

Since EF 6 does not have .HasPrincipalKey(), the principal columns should be specified with .Map():

builder.Entity<Settings>()
        .HasMany(s => s.Configs)
        .WithOne()
            .Map(cs =>
            {
                cs.MapLeftKey("NodeId", "UserId");
                cs.MapRightKey("NodeId", "UserId");
            });

Upvotes: 2

Related Questions