gpt4 book ai didi

.net - 继承和复合外键 - 一部分在基类中,另一部分在派生类中

转载 作者:行者123 更新时间:2023-12-03 14:20:48 26 4
gpt4 key购买 nike

我在为以下示例数据库架构(在 SQL Server 中)创建 Entity Framework 代码优先映射时遇到问题:

Database schema with composite foreign keys

每个表都包含一个 TenantId这是所有(复合)主键和外键( Multi-Tenancy )的一部分。

一个 CompanyCustomerSupplier我尝试通过 Table-Per-Type (TPT) 继承映射对此进行建模:

public abstract class Company
{
public int TenantId { get; set; }
public int CompanyId { get; set; }

public int AddressId { get; set; }
public Address Address { get; set; }
}

public class Customer : Company
{
public string CustomerName { get; set; }

public int SalesPersonId { get; set; }
public Person SalesPerson { get; set; }
}

public class Supplier : Company
{
public string SupplierName { get; set; }
}

使用 Fluent API 进行映射:

modelBuilder.Entity<Company>()
.HasKey(c => new { c.TenantId, c.CompanyId });

modelBuilder.Entity<Customer>()
.ToTable("Customers");

modelBuilder.Entity<Supplier>()
.ToTable("Suppliers");

基表 CompaniesAddress 具有一对多关系(每家公司都有一个地址,无论是客户还是供应商)我可以为这个关联创建一个映射:

 modelBuilder.Entity<Company>()
.HasRequired(c => c.Address)
.WithMany()
.HasForeignKey(c => new { c.TenantId, c.AddressId });

外键由主键的一部分组成 - TenantId - 和一个单独的列 - AddressId .这行得通。

正如您在数据库模式中看到的,从数据库的角度来看, Customer 之间的关系和 PersonCompany 之间基本上是同一种一对多关系。和 Address - 外键再次由 TenantId 组成(主键的一部分)和列 SalesPersonId . (只有一个客户有一个销售人员,而不是 Supplier,因此这次关系在派生类中,而不是在基类中。)

我尝试以与以前相同的方式为这种与 Fluent API 的关系创建映射:

modelBuilder.Entity<Customer>()
.HasRequired(c => c.SalesPerson)
.WithMany()
.HasForeignKey(c => new { c.TenantId, c.SalesPersonId });

但是当 EF 尝试编译模型时, InvalidOperationException被抛出:

The foreign key component 'TenantId' is not a declared property on type 'Customer'. Verify that it has not been explicitly excluded from the model and that it is a valid primitive property.



显然,我无法从基类中的属性和派生类中的另一个属性组成外键(尽管在数据库模式中,外键由派生类型的表 Customer 中的列组成)。

我尝试了两项修改以使其正常工作:
  • 更改了 Customer 之间的外键关联和 Person到一个独立的协会,即删除属性 SalesPersonId ,然后尝试映射:

    modelBuilder.Entity<Customer>()
    .HasRequired(c => c.SalesPerson)
    .WithMany()
    .Map(m => m.MapKey("TenantId", "SalesPersonId"));

    它没有帮助(我真的不希望,它会),异常(exception)是:

    Schema specified is not valid. ... Each property name in a type must be unique. Property name 'TenantId' was already defined.

  • 将 TPT 更改为 TPH 映射,即删除了两个 ToTable来电。但它抛出了同样的异常。

  • 我看到两种解决方法:
  • 介绍一个SalesPersonTenantId进入Customer类(class):

    public class Customer : Company
    {
    public string CustomerName { get; set; }

    public int SalesPersonTenantId { get; set; }
    public int SalesPersonId { get; set; }
    public Person SalesPerson { get; set; }
    }

    和映射:

    modelBuilder.Entity<Customer>()
    .HasRequired(c => c.SalesPerson)
    .WithMany()
    .HasForeignKey(c => new { c.SalesPersonTenantId, c.SalesPersonId });

    我对此进行了测试,并且可以正常工作。但是我会有一个新专栏SalesPersonTenantIdCustomers表除了 TenantId .此列是多余的,因为从业务角度来看,两列必须始终具有相同的值。
  • 放弃继承映射并在 Company 之间创建一对一映射和 CustomerCompany 之间和 Supplier . Company那么必须成为具体类型,而不是抽象类型,我将在 Company 中有两个导航属性.但是这个模型不能正确地表达一个公司要么是客户要么是供应商,并且不能同时是两者。我没有测试它,但我相信它会起作用。

  • 如果有人喜欢尝试它,我会将我测试过的完整示例(控制台应用程序,引用 EF 4.3.1 程序集,通过 NuGet 下载)粘贴到此处:

    using System;
    using System.Data.Entity;

    namespace EFTPTCompositeKeys
    {
    public abstract class Company
    {
    public int TenantId { get; set; }
    public int CompanyId { get; set; }

    public int AddressId { get; set; }
    public Address Address { get; set; }
    }

    public class Customer : Company
    {
    public string CustomerName { get; set; }

    public int SalesPersonId { get; set; }
    public Person SalesPerson { get; set; }
    }

    public class Supplier : Company
    {
    public string SupplierName { get; set; }
    }

    public class Address
    {
    public int TenantId { get; set; }
    public int AddressId { get; set; }

    public string City { get; set; }
    }

    public class Person
    {
    public int TenantId { get; set; }
    public int PersonId { get; set; }

    public string Name { get; set; }
    }

    public class MyContext : DbContext
    {
    public DbSet<Company> Companies { get; set; }
    public DbSet<Address> Addresses { get; set; }
    public DbSet<Person> Persons { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
    modelBuilder.Entity<Company>()
    .HasKey(c => new { c.TenantId, c.CompanyId });

    modelBuilder.Entity<Company>()
    .HasRequired(c => c.Address)
    .WithMany()
    .HasForeignKey(c => new { c.TenantId, c.AddressId });

    modelBuilder.Entity<Customer>()
    .ToTable("Customers");

    // the following mapping doesn't work and causes an exception
    modelBuilder.Entity<Customer>()
    .HasRequired(c => c.SalesPerson)
    .WithMany()
    .HasForeignKey(c => new { c.TenantId, c.SalesPersonId });

    modelBuilder.Entity<Supplier>()
    .ToTable("Suppliers");

    modelBuilder.Entity<Address>()
    .HasKey(a => new { a.TenantId, a.AddressId });

    modelBuilder.Entity<Person>()
    .HasKey(p => new { p.TenantId, p.PersonId });
    }
    }

    class Program
    {
    static void Main(string[] args)
    {
    Database.SetInitializer(new DropCreateDatabaseAlways<MyContext>());
    using (var ctx = new MyContext())
    {
    try
    {
    ctx.Database.Initialize(true);
    }
    catch (Exception e)
    {
    throw;
    }
    }
    }
    }
    }

    问题:有没有办法将上面的数据库模式映射到具有 Entity Framework 的类模型?

    最佳答案

    好吧,我似乎无法评论任何事情,所以我将其添加为答案。

    我为这个问题在 CodePlex 上创建了一个问题,希望他们能尽快调查。敬请关注!

    http://entityframework.codeplex.com/workitem/865

    CodePlex 问题的结果(同时已关闭)是问题中的场景不受支持,目前没有计划在不久的将来支持它。

    来自 CodePlex Entity Framework 团队的引述:

    This is part of a more fundamental limitation where EF doesn't support having a property defined in a base type and then using it as a foreign key in a derived type. Unfortunately this is a limitation that would be very hard to remove from our code base. Given that we haven't seen a lot of requests for it, it's not something we are planning to address at this stage so we are closing this issue.

    关于.net - 继承和复合外键 - 一部分在基类中,另一部分在派生类中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10961690/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com