c# - 实体类型的 EF 映射属性到具有 TPH 继承的多个表

标签 c# entity-framework inheritance ef-fluent-api tph

我想使用 Mapping Properties of an Entity Type to Multiple Tables in the Database (Entity Splitting)同时使用 Mapping the Table-Per-Hierarchy (TPH) Inheritance ,因此我的模型映射代码如下:

   modelBuilder
    .Entity<Person>()
    .HasKey(n => n.PersonId)
    .Map(map =>
    {
        map.Properties(p => new { p.Name });
        map.ToTable("dbo.Person");
    })
    .Map<Customer>(map =>
    {
        map.Requires("PersonType").HasValue("C");
        map.Properties(p => new { p.CustomerNumber });
        map.ToTable("dbo.Customer");
    });

基于以下基础数据库模式:

create table dbo.Person
(
    PersonId int not null identity(1,1) primary key,
    PersonType char(1) not null,
    Name varchar(50) not null
)

create table dbo.Customer
(
    PersonId int not null references dbo.Person (PersonId),
    CustomerNumber varchar(10) not null
)

但是,当 EF 尝试执行我的查询时:

ctx.People.ToList();

抛出以下异常信息:

Invalid column name 'PersonType'.

运行 SQL 配置文件时,它似乎试图在 dbo.Customer 的字段 PersonType 上使用值为 C 的谓词表,而不是在我的鉴别器所在的 dbo.Person 表上。

如果我使用一个或另一个功能,即只使用继承或只使用附加表映射,那么它可以工作,但我会放弃我的一些要求。

我正在做的事情可以用 EF Fluent API 完成吗?

感谢您的宝贵时间。

最佳答案

这可以通过在映射中涉及的所有表模式上创建 View 来实现:

create view dbo.vw_PersonExtended
as

    select
        p.Name, p.PersonId, p.PersonType, c.CustomerNumber
    from
        dbo.Person p
        left join dbo.Customer c on c.PersonId=p.PersonId

并将此 View 映射到基类类型 Person 并删除派生类表映射,如下所示:

   modelBuilder
    .Entity<Person>()
    .HasKey(n => n.PersonId)
    .Map(map =>
    {
        map.Properties(p => new { p.Name });
        map.ToTable("dbo.vw_PersonExtended");
    })
    .Map<Customer>(map =>
    {
        map.Requires("PersonType").HasValue("C");
        map.Properties(p => new { p.CustomerNumber });
    });

插入新实体会失败,因为 View 有多个基表,因此您必须使用 INSTEAD OF TRIGGER或使用 Fluent 代码将插入映射到存储过程:

    modelBuilder
        .Entity<Customer>()
        .MapToStoredProcedures(map => map.Insert(i => i.HasName("usp_InsertCustomer")));

并插入存储过程示例:

create procedure dbo.usp_InsertCustomer
    @Name varchar(50),
    @CustomerNumber varchar(50)
as
begin

        set nocount on
        declare @id int

        insert into dbo.Person (Name, PersonType)
        values (@Name, 'C')
        set @id = scope_identity()

        insert into dbo.Customer (PersonId, CustomerNumber)
        values (@id, @CustomerNumber)

        select @id as PersonId

end

显然,这种方法的缺点是所有的管道工作都涉及到它的工作。

关于c# - 实体类型的 EF 映射属性到具有 TPH 继承的多个表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34094470/

相关文章:

c# - 列表的面向对象编程问题

c# - LINQ 左连接可空值

c# - 是否可以更新获取的数据

c++ - 我可以使用对派生类实例的基类引用来初始化派生类引用吗?

c++ - 如何在 C++ 中更改继承类型的访问类型?

c# - C# 规范(团队?委员会?)是否考虑过这种对象创建语法?

c# - 如何在 WPF 列表框中排序?

c# - LINQ to Entities 在尝试解析列以进行不等式比较时无法识别方法 'Int32 Parse(System.String)' 方法

java - 如何限制匿名子类的创建(Java)

c# - 启动服务时出现 NLog 异常