9

I've been getting the following error message and I can't seem to grasp the reason why have I been getting it. Interestingly when adding migrations I didn't get any errors, but whenever I want to use the context I do get it.

The child/dependent side could not be determined for the one-to-one relationship between 'Block.JobBlock' and 'JobBlock.Block'. To identify the child/dependent side of the relationship, configure the foreign key property. If these navigations should not be part of the same relationship configure them without specifying the inverse.

A Job can have multiple JobBlocks (one-to-many); single Block can have only one JobBlock (one-to-one). So basically, a JobBlock is a reference table/entity used to reference Job and its Blocks. It is important to mention that a primary key in the JobBlock entity consists of two keys thus making it a compound primary key.

One might argue that a Block entity should already contain an IdJob property and that the JobBlock entity could be entirely dismissed, but there is some reasoning why it shouldn't be done this way so let's leave it as it is :)

Models:

public class Job : IEntity
{
    public Job()
    {
        JobBlocks = new HashSet<JobBlock>();
    }

    public Guid Id { get; set; } = Guid.NewGuid();
    public ICollection<JobBlock> JobBlocks { get; set; }
}

public class Block : IEntity
{
    public Guid Id { get; set; } = Guid.NewGuid();
    public JobBlock JobBlock { get; set; }
}


public class JobBlock : IEntity
{
    public Guid IdJob { get; set; }
    public Job Job { get; set; }

    public Guid IdBlock { get; set; }
    public Block Block { get; set; }
}

EF Configurations:

public class JobConfiguration : IEntityTypeConfiguration<Job>
{
    public void Configure(EntityTypeBuilder<Job> builder)
    {
        builder.HasKey(p => p.Id);
        builder.Property(p => p.Id) .IsRequired() .ValueGeneratedNever();

        builder.HasMany(e => e.JobBlocks)
            .WithOne(e => e.Job)
            .HasForeignKey(p => p.IdJob);
    }
}

public class BlockConfiguration : IEntityTypeConfiguration<Block>
{
    public void Configure(EntityTypeBuilder<Block> builder)
    {
        builder.HasKey(p => p.Id);
        builder.Property(p => p.Id).IsRequired().ValueGeneratedNever();

        builder.HasOne(e => e.JobBlock)
            .WithOne(e => e.Block)
            .HasForeignKey<JobBlock>(p => new { p.IdJob, p.IdBlock });
    }
}

public class JobBlockConfiguration : IEntityTypeConfiguration<JobBlock>
{
    public void Configure(EntityTypeBuilder<JobBlock> builder)
    {
        builder.HasKey(p => new { p.IdJob, p.IdBlock });
        builder.Property(p => p.IdJob).IsRequired();
        builder.Property(p => p.IdBlock).IsRequired();

        builder.HasOne(e => e.Job)
            .WithMany(e => e.JobBlocks)
            .HasForeignKey(p => p.IdJob);

        builder.HasOne(e => e.Block)
            .WithOne(e => e.JobBlock)
            .HasForeignKey<JobBlock>(p => new { p.IdJob, p.IdBlock });
    }
}
wegelagerer
  • 3,600
  • 11
  • 40
  • 60

1 Answers1

8

Problem is in your Block and JobBlock configuration. According to your requirement these two configurations should be as follows:

public class BlockConfiguration : IEntityTypeConfiguration<Block>
{
    public void Configure(EntityTypeBuilder<Block> builder)
    {
        builder.HasKey(p => p.Id);
        builder.Property(p => p.Id).IsRequired().ValueGeneratedNever();

        builder.HasOne(e => e.JobBlock)
            .WithOne(e => e.Block)
            .HasForeignKey<JobBlock>(p => p.IdBlock); // <--- Here it is
    }
}
public class JobBlockConfiguration : IEntityTypeConfiguration<JobBlock>
{
    public void Configure(EntityTypeBuilder<JobBlock> builder)
    {
        builder.HasKey(p => new { p.IdJob, p.IdBlock });

        // Key property is always required. You don't need to specify it explicitly.

        // You don't need to need specify one-one-one configuration
        //  between `Job and Block` and between `Block and JobBlock` in
        //  two places. You need to specify
        //  it only one place. That's why I have removed these from here.
    }
}
TanvirArjel
  • 30,049
  • 14
  • 78
  • 114
  • 3
    Good, but you don't need to / should not configure *any* (not only *one-to-one*) relationship in two places, so remove the other relationship configuration from `JobBlockConfiguration` as well. – Ivan Stoev Apr 01 '19 at 12:12
  • 2
    @IvanStoev Yes! You are correct! I did not notice this. Thanks a lot. – TanvirArjel Apr 01 '19 at 12:14
  • @TanvirArjel Unfortunately I still get the same result even though the configurations look exactly as in your answer. Error message is still the same. – wegelagerer Apr 01 '19 at 12:30
  • @wegelagerer I have tested in my side with a test project and everything generated perfectly without any issue. Please check your code again. And please also add the `IEntity` base to the question. – TanvirArjel Apr 01 '19 at 12:47
  • @TanvirArjel `IEntity` is empty, it isn't relevant for this case. Strange, because the code is 1:1 copy of your, but still doesn't work. Thank you anyway, I'll look into it. – wegelagerer Apr 01 '19 at 12:51
  • @wegelagerer Better directly copy my code and replace your `Block` and `JobBlock` configuration. I assume you did not make changes for `Block` block configuration as I have done. – TanvirArjel Apr 01 '19 at 12:53
  • 1
    @TanvirArjel - Ok, it's a bit embarassing to admit, but I've been using the wrong DbContext (I have 2 which are almost the same) :) I'll accept your answer since you gave me valuable infos on how to improve the configurations – wegelagerer Apr 01 '19 at 13:22