【问题标题】:Single Address table used to store addresses for many entities (using double foreign key) with Entity Framework单地址表,用于使用实体框架存储许多实体的地址(使用双外键)
【发布时间】:2017-06-01 04:26:40
【问题描述】:

我正在尝试使用单个Address 表来存储系统中具有通用KeyId 字段的多个实体的地址。一个客户可以有多个地址,一个供应商可以有多个地址。

地址类:

public int Id { get; set; }
public string Name { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Country { get; set; }
public string ZipCode { get; set; }
// These 2 fields make it so I can get all of the addresses for a single Customer or Vendor
public string EntityType { get; set; }
public int KeyId { get; set; }

// Navigation properties
public Customer Customer { get; set; }
public Vendor Vendor { get; set; }
public Location Location { get; set; }

客户类:

public int Id { get; set; }
public string Name { get; set; }

// Navigation properties
public IList<Address> Addresses { get; set; }

供应商类:

public int Id { get; set; }
public string Name { get; set; }

// Navigation properties
public IList<Address> Addresses { get; set; }

DbContext:

    builder.Entity<Customer>()
        .HasMany(c => c.Addresses)
        .WithOne(a => a.Customer)
        .HasForeignKey(a => a.KeyId);

    builder.Entity<Vendor>()
        .HasMany(v => v.Addresses)
        .WithOne(a => a.Vendor)
        .HasForeignKey(a => a.KeyId);

当尝试为数据库播种(添加供应商以及一些地址)时,我遇到了如下错误:

SqlException:MERGE 语句与 FOREIGN KEY 约束“FK_Address_Customer_KeyId”冲突。冲突发生在数据库“MyDatabase”、表“dbo.Customer”、列“Id”中。

我很确定这是因为参照完整性表明数据库中没有您尝试将 ID 存储在 KeyId 中的客户。

是否有任何可能的方法可以使用 EF 使用 FluentAPI 执行此类操作,还是我在玩火?如果所有属性都相同,那么必须创建一个名为 CustomerAddressVendorAddress 的类似乎太疯狂了。就好像我需要指定一个 EF 不允许你做的双外键。

附加说明:我想我将尝试在 SQL 管理工作室中设置所有内容,然后在 Visual Studio 中添加一个数据库优先的 EF 项目。我很想知道它将如何创建模型和数据库上下文。

【问题讨论】:

  • 我认为你所追求的在 EF 中被称为复杂类型
  • @Chef_Code 复杂类型不是我想要的。它不适用于客户可以有多个地址而供应商可以有多个地址的一对多关系。

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


【解决方案1】:

看起来客户/供应商与地址类之间的映射不正确。

Address 表中应该有不同的 ForeignKey 列指向不同的父表 [Customer/Vendor]。

因此,更改后您的实体将如下所示:

地址:

 public int Id { get; set; }
 public string Name { get; set; }
 public string Address1 { get; set; }
 public string Address2 { get; set; }
 public string City { get; set; }
 public string State { get; set; }
 public string Country { get; set; }
 public string ZipCode { get; set; }
 public int CustomerId { get; set; }
 public int VendorId { get; set; }


 // Navigation properties
 public Customer Customer { get; set; }
 public Vendor Vendor { get; set; }

DBContext

builder.Entity<Customer>()
    .HasMany(c => c.Addresses)
    .WithOne(a => a.Customer)
    .HasForeignKey(a => a.CustomerId);

builder.Entity<Vendor>()
    .HasMany(v => v.Addresses)
    .WithOne(a => a.Vendor)
    .HasForeignKey(a => a.VendorId);

希望它会有所帮助。

【讨论】:

  • 我忘记了这个选项。它不像我想要的那样干净。我真的很想使用 KeyId。另外,我会假设在您的解决方案中 CustomerId 和 VendorId 都应该可以为空?
  • 是的,CustomerId 和 VendorId 都是可为空的字段。如果没有 2 个单独的外键,EF 将无法映射正确的 Customer: AddressVendor: Address。假设我们在 Customer 表中有两条记录,CustomerId 为 1 和 2,在 Vendor 表中有两条记录,VendorId 为 1 和 2。现在,如果要将所有这些记录映射到 Address 表,将总共是 4 条记录,重复 'KeyId,这将导致 EF 决定哪个 KeyId 属于哪个客户/供应商希望消除您的疑问。谢谢
  • 知道了... 通常在地址表中会有一个名为 Type 的附加字段,它是 Customer 或 Vendor,所以当我进行选择时,我会做 address.where(a => a. Type == "Customer" && a.KeyId == 1).. 但我假设没有办法告诉 Entity Framework 额外使用 Type 作为外键的一部分。像这样的人让我想回到使用像 dapper 和数据库优先方法这样的 Micro ORM... 似乎有更多的灵活性。
  • 好吧.. 在这种情况下,您可以从 EntityFramework 设计 SQL 复合键,该键适用于多列。公共类地址 { [Key, Column(Order = 0)] public int KeyId { get;放; } // 客户/供应商 ID [Key, Column(Order = 1)] public string MainTable { get;放; } //客户/供应商 }
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-17
相关资源
最近更新 更多