Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在实体框架6中混合TPH和TPT? 初始情况_C#_Entity Framework_Inheritance_Ef Code First_Entity Framework 6 - Fatal编程技术网

C# 如何在实体框架6中混合TPH和TPT? 初始情况

C# 如何在实体框架6中混合TPH和TPT? 初始情况,c#,entity-framework,inheritance,ef-code-first,entity-framework-6,C#,Entity Framework,Inheritance,Ef Code First,Entity Framework 6,我有一个使用现有数据库的应用程序,目前使用NHibernate作为O/R映射器。 现在我需要先使用代码和流畅的API配置迁移到实体框架6.1.1 但是现在我对数据模型的一部分有一个问题,因为它使用不同类型的继承策略(TPT和TPH) 结构 注意:在这里发布完整的数据模型对我来说似乎有点太大了,所以我在一个小的POC程序中重现了我面临的问题 表中用作判别符的列称为Type 基于此,我添加了一个抽象类Intermediate\u TPH作为中间层: 一些示例数据:ID为3的条目属于继承的类型 代

我有一个使用现有数据库的应用程序,目前使用NHibernate作为O/R映射器。
现在我需要先使用代码流畅的API配置迁移到实体框架6.1.1

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

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

表中用作判别符的列称为
Type

基于此,我添加了一个抽象类
Intermediate\u TPH
作为中间层:

一些示例数据:ID为3的条目属于继承的类型

代码 以下是我的实体类和我的上下文类:

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; }
}
class MyContext:DbContext
{
公共MyContext(字符串连接字符串)
:基本(连接字符串)
{
}
公共DbSet TPH_集{get;Set;}
公共DbSet TPT_集{get;Set;}
公共数据库集另一个_集{get;Set;}
模型创建时受保护的覆盖无效(DbModelBuilder modelBuilder)
{
建模者
.实体()
.ToTable(“基准”);
建模者
.实体()
.Map(t=>t.Requires(“Type”).HasValue(1));
建模者
.实体()
.Map(t=>t.Requires(“Type”).HasValue(2));
建模者
.实体()
.Map(t=>t.ToTable(“继承的”);
建模者
.实体()
.ToTable(“SomethingElse”)
.HasKey(t=>t.Id);
}
}
公共抽象类BaseEntity
{
公共虚拟整数Id{get;set;}
公共虚拟字符串标题{get;set;}
}
公共类继承的\u TPH:BaseEntity
{
}
公共抽象类中间\u TPT:BaseEntity
{
}
公共类继承\u TPT:中间\u TPT
{
公共虚拟字符串注释{get;set;}
}
公共类某物
{
公共虚拟字符串描述{get;set;}
公共虚拟整数Id{get;set;}
}
运行以下代码将给我一个错误

    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 ); }
        }
    }
static void Main(字符串[]args)
{
Database.SetInitializer(null);
var ctx=new MyContext(@“数据源=(本地);初始目录=nh_ef;集成安全性=true”);
尝试
{
//访问你的TPH工作得很好
foreach(ctx.TPH_集中的var项)Console.WriteLine(“{0}:{1}”,item.Id,item.Title);
//访问TPT工作正常
foreach(ctx.TPT_集合中的var项)Console.WriteLine(“{0}:{1}({2})”,item.Id,item.Title,item.Comment);
//访问另一个实体时发生错误:
foreach(ctx.other_Set中的var项)Console.WriteLine(“{0}:{1}”,item.Id,item.Description);
}
捕获(例外情况除外)
{
Console.WriteLine(例如消息);
如果(ex.InnerException!=null){Console.WriteLine(ex.InnerException.Message);}
}
}
输出 该程序产生以下输出:

1:辛普森
2:Johnson
3:Smith(更多关于Smith的详细信息)
4:Miller(有关Miller的更多详细信息)
准备命令定义时出错。有关详细信息,请参见内部异常

(26,10):错误3032:映射从第14,26行开始的片段时出现问题:EntityTypes PoC.Inherited_TPH、PoC.Inherited_TPT正在映射到表BaseEntity中的相同行。映射条件可用于区分这些类型映射到的行

问题: 正如您所看到的,映射似乎有效,因为我可以从
继承的\u TPT
继承的\u TPH
加载所有数据。但是当访问另一个实体时,我得到一个异常


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

我终于自己找到了解决方案。我会把它贴在这里,以防其他人需要同样的行为

  • 在这种情况下,不需要中间层
  • 鉴别器仅用于TPH
因此,我们需要做的就是更改映射的定义:

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 );
}
模型创建时受保护的覆盖无效(DbModelBuilder modelBuilder)
{
//不变
建模者
.实体()
.ToTable(“基准”);
//---改变---
modelBuilder.Entity()
//TPH=>鉴别器
.Map(m=>m.Requires(“Type”).HasValue(1.IsOptional())
//TPT=>映射到表
.Map(m=>m.ToTable(“继承的_TPT”);
//不变
建模者
.实体()
.ToTable(“SomethingElse”)
.HasKey(t=>t.Id);
}

Inherited\u TPT“如何知道必须在type列中插入2?如果我实现上述解决方案,我会得到一个异常,类型是必需的列,并且我试图插入一个空值。提前感谢您提供的任何反馈:)自从我不得不处理这个问题以来,已经过了一段时间,所以我可能记错了-但是我认为
Type
列应该可以为空,因为
.iso可选()
继承的\u TPT
不需要在
类型中插入值,因为它映射到另一个表(在Id上联接)
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 );
}