You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于多列在.NET中创建Invoice与ContractAccount的多对多关系

解决方案

.NET 生态下的EF(包括EF Core和EF6)完全支持基于多列组合的关联关系配置,你不需要手动写关联筛选逻辑,具体实现步骤如下:

实现步骤

步骤1:给实体添加导航属性

首先在Invoice实体类中添加关联ContractAccount的导航属性:

public class Invoice
{
    // 原有属性 Id、InvoiceNumber、CustomerId、ConsumptionPointId 等
    public ICollection<ContractAccount> ContractAccounts { get; set; }
}

然后在ContractAccount实体类中添加反向导航属性:

public class ContractAccount
{
    // 原有属性 Id、ContractAccountNumber、CustomerId、ConsumptionPointId、IsCurrentDelivery 等
    public ICollection<Invoice> Invoices { get; set; }
}

步骤2:配置复合键多对多关系

在你继承自DbContext的上下文类的OnModelCreating方法中添加如下配置:

若使用EF Core:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    // 配置Invoice和ContractAccount的多对多复合关联
    modelBuilder.Entity<Invoice>()
        .HasMany(i => i.ContractAccounts)
        .WithMany(ca => ca.Invoices)
        .UsingEntity(
            j => j
                .HasOne<ContractAccount>()
                .WithMany()
                .HasForeignKey("CustomerId", "ConsumptionPointId")
                .HasPrincipalKey<ContractAccount>(ca => new { ca.CustomerId, ca.ConsumptionPointId }),
            j => j
                .HasOne<Invoice>()
                .WithMany()
                .HasForeignKey("CustomerId", "ConsumptionPointId")
                .HasPrincipalKey<Invoice>(i => new { i.CustomerId, i.ConsumptionPointId })
        );

    // 可选:添加全局筛选器,默认只查询IsCurrentDelivery为true的ContractAccount,省去手动加条件
    modelBuilder.Entity<ContractAccount>()
        .HasQueryFilter(ca => ca.IsCurrentDelivery);
}

若使用EF6:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Invoice>()
        .HasMany(i => i.ContractAccounts)
        .WithMany(ca => ca.Invoices)
        .Map(m => 
        {
            m.MapLeftKey("CustomerId", "ConsumptionPointId");
            m.MapRightKey("CustomerId", "ConsumptionPointId");
            m.ToTable("InvoiceContractAccountMappings");
        });
}

最终调用方式

配置完成后,你就可以直接通过导航属性获取对应ContractAccount,不需要手动写关联筛选逻辑:

// 直接获取对应有效的ContractAccount
var targetContractAccount = invoice.ContractAccounts.FirstOrDefault();

注意事项

  • 确保Invoice和ContractAccount中的CustomerId、ConsumptionPointId属性的类型完全一致,否则关联配置会报错
  • 如果你后续需要查询IsCurrentDelivery为false的记录,调用IgnoreQueryFilters()方法即可取消全局筛选器的限制:
    var allAccounts = context.ContractAccounts.IgnoreQueryFilters().ToList();
    
  • 如果需要对中间表做额外的字段扩展,可以自定义中间表实体类替换隐式中间表,配置逻辑基本一致。

内容的提问来源于stack exchange,提问作者Robert

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 09:36:04