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

时间:2015-12-04 17:53:20

标签: 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配置文件时,它似乎试图在PersonType表上使用值为C的字段dbo.Customer上而不是dbo.Person上使用谓词我的鉴别者确实在哪里。

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

我可以用EF Fluent API完成我的工作吗?

感谢您的时间。

1 个答案:

答案 0 :(得分:0)

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

Event::on(\yii\web\Response::className(), \yii\web\Response::EVENT_AFTER_SEND, function ($event) {
          unlink($event->response->filename);  
});

将此视图映射到基类类型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 并删除派生类表映射,如下所示:

Person

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

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

并将存储过程示例插入:

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

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