首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在实体框架6中混合TPH和TPT?

如何在实体框架6中混合TPH和TPT?
EN

Stack Overflow用户
提问于 2014-11-26 10:16:44
回答 1查看 1.3K关注 0票数 6

初始情况

我有一个使用现有数据库的应用程序,目前使用NHibernate作为O/R。

现在,我需要使用CodeFluent API配置迁移到实体框架6.1.1

但是现在我遇到了数据模型的一部分问题,因为它使用了不同类型的继承策略(TPT和TPH)。

结构

注意:在这里发布完整的数据模型对我来说有点太大了,所以我在一个小型POC程序中重现了我面临的问题。

代码语言:javascript
复制
CLASS                  | TABLE              | TYPE
-----------------------+--------------------+------
BaseEntity (abstract)  | BaseTable          |
Inherited_TPH          | BaseTable          |  1
Inherited_TPT          | Inherited_TPT      |  2

表中用作描述器的列称为Type

基于this answer,我添加了一个抽象类Intermediate_TPH作为中间层:

一些示例数据:使用ID=3的条目是Inherited_TPT类型的

代码

这些是我的实体类和上下文类:

代码语言:javascript
复制
class MyContext : DbContext
{
    public MyContext ( string connectionString )
        : base ( connectionString )
    {
    }

    public DbSet<Inherited_TPH> TPH_Set { get; set; }
    public DbSet<Inherited_TPT> TPT_Set { get; set; }
    public DbSet<SomethingElse> Another_Set { get; set; }

    protected override void OnModelCreating ( DbModelBuilder modelBuilder )
    {
        modelBuilder
        .Entity<BaseEntity> ()
        .ToTable ( "BaseTable" );

        modelBuilder
        .Entity<Inherited_TPH> ()
        .Map ( t => t.Requires ( "Type" ).HasValue ( 1 ) );

        modelBuilder
        .Entity<Intermediate_TPT> ()
        .Map ( t => t.Requires ( "Type" ).HasValue ( 2 ) );

        modelBuilder
        .Entity<Intermediate_TPT> ()
        .Map<Inherited_TPT> ( t => t.ToTable ( "Inherited_TPT" ) ); 

        modelBuilder
        .Entity<SomethingElse> ()
        .ToTable ( "SomethingElse" )
        .HasKey ( t => t.Id );
    }
}

public abstract class BaseEntity
{
    public virtual int Id { get; set; }
    public virtual string Title { get; set; }
}
public class Inherited_TPH : BaseEntity
{
}
public abstract class Intermediate_TPT : BaseEntity
{
}
public class Inherited_TPT : Intermediate_TPT
{
    public virtual string Comment { get; set; }
}
public class SomethingElse
{
    public virtual string Description { get; set; }
    public virtual int Id { get; set; }
}

运行以下代码将给出一个错误。

代码语言:javascript
复制
    static void Main ( string[] args )
    {
        Database.SetInitializer<MyContext> ( null );
        var ctx = new MyContext ( @"Data Source=(local);Initial Catalog=nh_ef;Integrated Security=true" );
        try
        {
            // Accessing Inherited_TPH works just fine
            foreach ( var item in ctx.TPH_Set ) Console.WriteLine ( "{0}: {1}", item.Id, item.Title );
            // Accessing Inherited_TPT works just fine
            foreach ( var item in ctx.TPT_Set ) Console.WriteLine ( "{0}: {1} ({2})", item.Id, item.Title, item.Comment );
            // The rror occurs when accessing ANOTHER entity:
            foreach ( var item in ctx.Another_Set ) Console.WriteLine ( "{0}: {1}", item.Id, item.Description );
        }
        catch ( Exception ex )
        {
            Console.WriteLine ( ex.Message );
            if( ex.InnerException != null ) { Console.WriteLine ( ex.InnerException.Message ); }
        }
    }

输出

该程序产生以下输出:

1:辛普森 2: Johnson 3:史密斯(关于史密斯的更多细节) 4:米勒(更多关于米勒的详细信息) 准备命令定义时出错。有关详细信息,请参阅内部异常。(26,10):错误3032:从第14行开始的片段映射问题,第26行:EntityTypes PoC.Inherited_TPH,PoC.Inherited_TPT映射到表BaseEntity中的相同行。映射条件可用于区分这些类型映射到的行。

问题

正如您所看到的,映射似乎可以运行,因为我可以从Inherited_TPTInherited_TPH加载所有数据。但是当访问另一个实体时,我得到一个异常

如何配置映射以消除此错误并能够访问现有的数据库结构?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-09-10 09:17:43

我终于自己找到了解决办法。我会把它发到这里以防别人需要同样的行为..。

  • 在这种情况下不需要中间层。
  • 只有TPH才需要鉴别器。

因此,我们所需要做的就是更改映射的定义:

代码语言:javascript
复制
protected override void OnModelCreating ( DbModelBuilder modelBuilder )
{
    // Not changed
    modelBuilder
        .Entity<BaseEntity> ()
        .ToTable ( "BaseTable" );


    // --- CHANGED ---
    modelBuilder.Entity<BaseEntity> ()
        // TPH => Discriminator
        .Map<Inherited_TPH> ( m => m.Requires ( "Type" ).HasValue ( 1 ).IsOptional () ) 
        // TPT => Mapping to table
        .Map<Inherited_TPT> ( m => m.ToTable ( "Inherited_TPT" ) ); 

    // Not changed
    modelBuilder
        .Entity<SomethingElse> ()
        .ToTable ( "SomethingElse" )
        .HasKey ( t => t.Id );
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27146490

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档