2

エンティティ タイプのプロパティをデータベース内の複数のテーブルにマッピングする (エンティティ分割)と同時に、階層ごとのテーブル (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");
    });

次の基礎となるデータベース スキーマに基づきます。

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値を持つフィールドで述語を使用しようとしているように見えます。Cdbo.Customerdbo.Person

どちらか一方の機能、つまり継承のみまたは追加のテーブル マッピングのみを使用すると機能しますが、要件の一部が失われます。

私がやっていることは EF Fluent API で実行できますか?

御時間ありがとうございます。

4

1 に答える 1

0

これは、マッピングに含まれるすべてのテーブル スキーマのビューを作成することで実現できます。

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

明らかに、このアプローチの欠点は、これを機能させるために必要なすべての配管作業です。

于 2015-12-11T08:52:10.230 に答える