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

EF Mapping Properties of an Entity Type to Multiple Tables with TPH Inheritance

我想用Mapping Properties of an Entity Type to Multiple Tables in the Database (Entity Splitting) whilst as the same time using 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 配置文件似乎试图在字段 PersonType 上使用谓词 dbo.Customer C table,而不是 dbo.Person table 我的鉴别器所在的位置。

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

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

感谢您的宝贵时间。

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

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

并将此视图映射到基础 class 类型 Person 并删除派生的 class table 映射,如下所示:

   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 });
    });

插入新实体会失败,因为视图有多个基 table,因此您必须使用 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

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