Отношение один-к-одному в EF Core (дочерняя / зависимая сторона не может быть определена для отношения один-к-одному)

Я получаю следующее сообщение об ошибке и не могу понять причину, почему я его получаю. Интересно, что при добавлении миграций я не получаю никаких ошибок, но всякий раз, когда я хочу использовать контекст, я получаю его.

Дочерняя / зависимая сторона не может быть определена для отношения один-к-одному между "Block.JobBlock" и "JobBlock.Block". Чтобы определить дочернюю / зависимую сторону отношения, настройте свойство внешнего ключа. Если эти переходы не должны быть частью одного и того же отношения, настройте их без указания обратного.

Job может иметь несколько JobBlocks (один ко многим); не замужем Block может иметь только один JobBlock (один к одному). Так что в основном JobBlock справочная таблица / сущность, используемая для ссылки Job И его Blocks, Важно отметить, что первичный ключ в JobBlock сущность состоит из двух ключей, что делает его составным первичным ключом.

Можно утверждать, что Block сущность уже должна содержать IdJob собственность и что JobBlock сущность может быть полностью отклонена, но есть некоторые причины, почему это не должно быть сделано таким образом, так что давайте оставим это как есть:)

Модели:

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:

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 });
    }
}

1 ответ

Решение

Проблема в вашем Block а также JobBlock конфигурации. Согласно вашему требованию эти две конфигурации должны быть следующими:

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.
    }
}