Jogge
Jogge

Reputation: 1852

How to configure relationship with a constant in the composite key for Entity Framework Core?

public class Order
{
    public int Id { get; set; }
    public string Type { get; set; }
}

Order has the composite key (Id, Type).

public class SalesOrderItem
{
    public int Id { get; set; }
    public int OrderId { get; set; }
    public Order Order { get; set; }
}

SalesOrderItem has the key Id.

I want to configure a relation between SalesOrderItem and Order. SalesOrderItem does not have an OrderType column that can be used to create the composite key for the relation. OrderType is always SAL when working with SalesOrderItem.

I have tried to configure the relation by setting a constant in the foreign key part:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder
        .Entity<Order>()
        .HasKey(o => new { o.Id, o.Type });

    modelBuilder
        .Entity<SalesOrderItem>()
        .HasKey(s => s.Id);

    modelBuilder
        .Entity<Order>()
        .HasMany<SalesOrderItem>()
        .WithOne(salesOrderItem => salesOrderItem.Order)
        .HasForeignKey(salesOrderItem => new {salesOrderItem.OrderId, Type = "SAL"});
}

This does not work.

What can I do?

Upvotes: 2

Views: 1482

Answers (2)

ish1313
ish1313

Reputation: 319

bit different view on the same problem. (i am moving project from plain sqlrecord to ef core, so it is data first. and data structure can't be modified for now. so it is not optimal in many parts)

i have tasks, which may have few steps and each step may have a comment. comments are stored in separate table. and other objects in database may have comments in the same table. so the data structure is

  public partial class Comment
    {
        public int Id { get; set; }
        public int RefType { get; set; }
        public int RefId { get; set; }
        public int? RefId1 { get; set; }
        public string Comment1 { get; set; }
    }

where RefType is referring object type

Refid is id of referring object

RefId1 is second id if needed

enities (partially)

public enum RefType : int { UNKNOWN = 0, TASK, TaskStep };
public partial class TaskHist
    {
        public int TaskId {get;set;}
        public ICollection<TaskStep> TaskSteps { get; set; }
    }

    public partial class TaskStep
    {
        public int Id { get; set; }
        public int TaskId { get; set; }
        public int StepNum { get; set; }
        public tsComment comment { get; set; }
    }

    // tsComment only for descriminator
    public class tsComment : Comment
    { 
    }

model configuration partially

   modelBuilder.Entity<Comment>(entity =>
            {
                entity.HasKey(c => c.Id);
                entity.HasDiscriminator<int>(c=>c.RefType)
                        .HasValue<Comment>(0)
                        .HasValue<tsComment>((int)RefType.TaskStep)
                        .IsComplete(false);

            });
   modelBuilder.Entity<TaskHist>(entity =>
            {
                entity.HasKey(t => t.TaskId);
                entity.HasMany(t=>t.TaskSteps).WithOne().HasForeignKey(t=>t.TaskId);
            });
   modelBuilder.Entity<TaskStep>(entity =>
            {
                entity.HasOne(t => t.comment).WithOne()
                      .HasForeignKey<TaskStep>(c=> new {c.TaskId, c.StepNum})
                      .HasPrincipalKey<tsComment>(c=> new {c.RefId, c.RefId1});
            });





Upvotes: 0

Eldar
Eldar

Reputation: 10790

You cannot use constant as a reference but instead you can derive another table like this :

public class SalesOrder : Order
{
}

public class SalesOrderItem
{
    public int Id { get; set; }
    public int OrderId { get; set; }
    public SalesOrder Order { get; set; }
}

and configure your salesorder like this

modelBuilder.Entity<Order>()
    .HasDiscriminator(t => t.Type)
    .HasValue<SalesOrder>("SAL");

then map with just foreign key to sales order

modelBuilder
    .Entity<Order>()
    .HasMany<SalesOrderItem>()
    .WithOne(salesOrderItem => salesOrderItem.Order)
    .HasPrincipalKey(salesOrderItem => salesOrderItem.OrderId);

EDIT : Since it has composite index using principal key is the option as @Jogge commented.

Upvotes: 2

Related Questions