实体框架核心-将两个联接映射到同一张表

时间:2019-12-02 09:09:02

标签: c# entity-framework entity-framework-core

我有两个表Clients和Jobs。客户可以有许多工作。但是,我在Jobs上有第二种关系,该关系也应回溯到称为WarrantyCompany的客户。基本上,保修公司也是客户。客户/工作关系是主要关系,但是我想第二次返回客户表以获取保修公司的详细信息。

这是“客户”表:

using JobsLedger.DATA.Entities.Interfaces;
using JobsLedger.DATA.Interfaces;
using System;
using System.Collections.Generic;

namespace JobsLedger.DATA.Entities
{
#nullable enable
    public class Client : IEntityBase, IAuditedEntityBase
    {

        public Client()
        {
            Jobs = new List<Job>();

        }
        public int Id { get; set; }

        // One warranty company client to a job.
        public int? WarrantyCompanyId { get; set; }
        public Job? WarrantyCompany { get; set; }

        // One suburb to a client.
        public int? SuburbId { get; set; }
        public Suburb? Suburb { get; set; }

        // If its a warranty company then we simply link it one to one to the brand id.
        public Brand? Brand { get; set; }

        public virtual ICollection<Job> Jobs { get; set; } = default!;

        public virtual ICollection<Job> WarrantyCompanyJobs { get; set; } = default!;
    }
#nullable disable
}

我正在使用以下方式引用作业表:

// One warranty company client to a job.
public int? WarrantyCompanyId { get; set; }
public Job? WarrantyCompany { get; set; }

工作表如下:

using JobsLedger.DATA.Entities.Interfaces;
using JobsLedger.DATA.Interfaces;
using System.Collections.Generic;

namespace JobsLedger.DATA.Entities
{
    public class Job : IEntityBase, IAuditedEntityBase
    {
#nullable enable
        public Job()
        {
            Visits = new List<Visit>();
        }

        public int Id { get; set; }

        public int? WarrantyCompanyId { get; set; }

        public Client? WarrantyCompany { get; set; }

        public int ClientId { get; set; } = default!;

        public Client Client { get; set; } = default!;

    }
#nullable disable
}

在此表中,我使用以下方法引用到client表:

public int? WarrantyCompanyId { get; set; }
public Client? WarrantyCompany { get; set; }

我正在使用Entity Framework Core Fluent API创建关系。

我决定从客户的角度考虑两种关系:

// Two one to many relationships between client and job.
modelBuilder.Entity<Client>()
    .HasMany(t => t.Jobs)
    .WithOne(g => g.Client)
    .HasForeignKey(g => g.ClientId)
    .OnDelete(DeleteBehavior.Restrict);

// Same table but a client can also be a warranty agent.
modelBuilder.Entity<Client>()
    .HasMany(a => a.Jobs)
    .WithOne(b => b.WarrantyCompany)
    .HasForeignKey(b => b.WarrantyCompanyId);

我尝试创建迁移,但是出现以下错误:

  

无法在“ Client.Jobs”和“ Client.Jobs”之间建立关系   'Job.WarrantyCompany',因为两者之间已经存在关系   “ Client.Jobs”和“ Job.Client”。导航属性只能   参加一个单一的关系。

这是不言而喻的。我还尝试从作业表的角度创建关系:

modelBuilder.Entity<Job>()
    .HasOne(a => a.Client)
    .WithOne(b => b.WarrantyCompany)
    .HasForeignKey<Client>(b => b.WarrantyCompanyId);

当有两个返回到同一客户表时,我发现无法可视化这种关系。

简而言之,本质上,我有一个可以从事一对多工作的客户,但是对于这些工作,我可能会设置一个可选的保修公司,其中保修公司是客户。客户与工作之间的两种关系。

这两个表之间如何具有主要关系以及次要可选关系,并且次要保修公司关系是一对一还是一对多?

2 个答案:

答案 0 :(得分:1)

由于两个关系被映射到Client类中的同一Jobs集合而发生此问题。由于实际上存在两个关系,因此它们不能重用相同的属性。

您的客户模型已经具有第二种关系的集合。您只需要修复映射。

    // First client/job relationship
    modelBuilder.Entity<Client>()
        .HasMany(t => t.Jobs)
        .WithOne(g => g.Client)
        .HasForeignKey(g => g.ClientId)
        .OnDelete(DeleteBehavior.Restrict);

    // Second client/job relationship (warranty)
    modelBuilder.Entity<Client>()
        .HasMany(a => a.WarrantyCompanyJobs)
        .WithOne(b => b.WarrantyCompany)
        .HasForeignKey(b => b.WarrantyCompanyId);

答案 1 :(得分:1)

为了简化可读性,我简化了表格属性。

客户表:

public class Client 
{
    public int Id { get; set; }

    // One warranty company client to a job.
    public int? WarrantyCompanyId { get; set; }
    public Job? WarrantyCompany { get; set; }

    public ICollection<Job> Jobs { get; set; } = default!;

    public ICollection<Job> WarrantyCompanyJobs { get; set; } = default!;
}

和作业表:

public class Job
{
    public int Id { get; set; }

    public int? WarrantyCompanyId { get; set; }
    public Client? WarrantyCompany { get; set; }


    public int ClientId { get; set; } = default!;
    public Client Client { get; set; } = default!;

}

为了进行配置,我创建了一个JobConfig

public class JobConfig : IEntityTypeConfiguration<Job>
    {
        public void Configure(EntityTypeBuilder<Job> builder)
        {
            builder.HasOne(s => s.Client)
            .WithMany(g => g.Jobs)
            .HasForeignKey(f => f.ClientId);

            builder.HasOne(s => s.WarrantyCompany)
                .WithMany(g => g.WarrantyCompanyJobs)
                .HasForeignKey(f => f.WarrantyCompanyId);
        }
    }

Context类中,假设上下文类名称为ProjectContext,则我重写OnModelCreating方法。

public class ProjectContext: DbContext
{
    public ProjectContext()
    {

    }

    public Client Client { get; set; }
    public Job Job { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.ApplyConfiguration(new JobConfig());
    }
 }

它将生成一个这样的表和关系。

enter image description here