通过多列在两个实体之间创建多对多关系

Create many-to-many relationship between two entities via multiple columns

我有以下四个表:

客户

Id
FirstName
...

消费点数

Id
Address
...

发票

Id
InvoiceNumber
CustomerId
ConsumptionPointId
...

合约账户

Id
ContractAccountNumber
CustomerId
ConsumptionPointId
IsCurrentDelivery
...

我想获取发票的 ContractAccountNumber。

是否可以在这两者之间创建某种关系以直接访问发票的 ContractAccount?

目前我正在做类似的事情:

invoice.Customer.ContractAccounts
    .Where(ca => ca.ConsumptionPoint == invoice.ConsumptionPoint &&
    ca.IsCurrentDelivery == true).FirstOrDefault();

update in SQL 我只想做一个有多个条件的连接:

SELECT i.Id AS InvoiceId, ca.Id AS ContractAccountId, 
ca.ContractAccountNumber
FROM Invoices i
LEFT JOIN ContractAccounts ca
ON i.ConsumptionPointId = ca.ConsumptionPointId
AND i.CustomerId = ca.CustomerId
WHERE ca.IsCurrentDelivery = 1

更新 2:

基本上我只想去掉 Where 子句中的 ca.ConsumptionPoint == invoice.ConsumptionPoint 并想在关系中定义它。

实际上这是一个多对多关系:一个发票可以 link 到多个 ContractAccount(通过不同的 Customer/ConsumptionPoint 组合),一个 ContractAccount 可以 link 到多个发票。有没有办法告诉 .net 建立多对多关系,基于两个自定义列的组合?

我认为您不需要两把钥匙。使用 EF 核心,您可以创建这样的关系:

发票:

public class Invoice
{
  public int Id {get; set;}
  public int InvoiceNumber {get; set;}
  public int CustomerId {get; set;}
  public Customer Customer {get; set;}
  public int ConsumptionPointId {get; set;}

  public int ContractAccountId {get; set;}
  public ContractAccount ContractAccount {get; set;}
}
public class ContractAccount
{
  public int Id {get; set;}
  public int ContractAccountNumber {get; set;}
  public bool IsCurrentDelivery {get; set;}
}

然后配置:

modelBuilder.Entity<Invoice>()
  .HasOne(b => b.ContractAccount)
  .WithOne()
  .HasForeignKey<Invoice>(b => b.ContractAccountId);

//probably already exists in your code
modelBuilder.Entity<Invoice>()
  .HasOne(b => b.Customer )
  .WithMany()
  .HasForeignKey(b => b.CustomerId);

然后您可以直接从发票中访问它:invoice.ContractAccount

经过更深入的调查,我找到了解决方案。

基本上就是多对多的关系。因此我们可以将适当的属性添加到 Invoice 和 ContractAccount 模型:

public class Invoice
{
    [Key]
    public long Id { get; set; }
    public Customer Customer { get; set; }
    public ConsumptionPoint ConsumptionPoint { get; set; }
    public virtual ICollection<ContractAccount> ContractAccounts { get; set; }
}

public class ContractAccount
{
    [Key]
    public long Id { get; set; }
    public Customer Customer { get; set; }
    public ConsumptionPoint ConsumptionPoint { get; set; }
    public ICollection<Invoice> Invoices { get; set; }
}

现在,我们只需手动配置关系:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);
    modelBuilder.Entity<Invoice>()
        .HasMany(i => i.ContractAccounts)
        .WithOne()
        .HasForeignKey(ca => new { ca.CustomerId, ca.ConsumptionPointId })
        .HasPrincipalKey(i => new { i.CustomerId, i.ConsumptionPointId });
    modelBuilder.Entity<ContractAccount>()
        .HasMany(ca => ca.Invoices)
        .WithOne()
        .HasForeignKey(i => new { i.CustomerId, i.ConsumptionPointId })
        .HasPrincipalKey(ca => new { ca.CustomerId, ca.ConsumptionPointId });
}

就是这样。现在我可以做类似的事情:

invoice.ContractAccounts
    .Where(ca => ca.IsCurrentDelivery == true).FirstOrDefault();

比以前好多了。

感谢您的评论,为我指明了正确的方向。