简体   繁体   English

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

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

I would like to use 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 , therefore my model mapping code is as follows: 我想在数据库中使用实体类型的映射属性到多个表(实体拆分) ,同时使用“ 按表分层结构”(TPH)继承映射,因此我的模型映射代码如下:

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

Based upon the following underlying database schema: 基于以下基础数据库架构:

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
)

However, when the EF tries to execute my query: 但是,当EF尝试执行我的查询时:

ctx.People.ToList();

The following exception message is thrown: 引发以下异常消息:

Invalid column name 'PersonType'.

Running a SQL profile it would appear that its trying to use a predicate on the field PersonType with value C on the dbo.Customer table, rather than on the dbo.Person table where my discriminator really is. 运行一个SQL概要文件,它似乎试图在dbo.Customer表上而不是在我的鉴别器所在的dbo.Person表上使用值为C PersonType字段上的谓词。

If I use one or the other feature, ie only the inheritance or only the additional table mapping then it works but then I forfeit some of my requirements. 如果我使用一个或另一个功能,即仅继承或仅使用其他表映射,则它可以工作,但是我放弃了一些要求。

Can what I'm doing be done with the EF Fluent API? EF Fluent API可以完成我的工作吗?

Thanks for your time. 谢谢你的时间。

This can be achieved by creating a view on all the table schemas involved in the mapping: 这可以通过在映射中涉及的所有表模式上创建视图来实现:

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

And mapping this view to the base class type Person and removing the derived class table mapping as follows: 然后将此视图映射到基类类型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 });
    });

This would fail on inserting new entities as the view has more than one base table, therefore you'd have to use an INSTEAD OF TRIGGER or map the insertion to a stored procedure with Fluent code as: 由于视图具有多个基表,因此在插入新实体时将失败,因此您必须使用INSTEAD OF TRIGGER或使用Fluent代码将插入映射到存储过程,如下所示:

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

And insert stored procedure example as: 并插入存储过程示例为:

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

Obviously the drawback with this approach is all of the plumbing work involved with getting this working. 显然,这种方法的缺点是使这种工作涉及到所有的管道工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM