【问题标题】:EF Mapping Properties of an Entity Type to Multiple Tables with TPH InheritanceEF 将实体类型的属性映射到具有 TPH 继承的多个表
【发布时间】:2015-12-04 17:53:20
【问题描述】:

我想使用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 表上使用值为 C 的字段 PersonType 上的谓词,而不是在我的鉴别器真正所在的 dbo.Person 表上使用谓词。

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

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

感谢您的宝贵时间。

【问题讨论】:

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


    【解决方案1】:

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

    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 并删除派生类表映射,如下所示:

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

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

    很明显,这种方法的缺点是所有的管道工作都需要完成。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-02
      • 2015-02-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多