EF代码首先是多级继承问题

时间:2017-07-05 10:28:59

标签: entity-framework ef-code-first

我有一个由以下类组成的多级继承heriarchy:

public abstract class BasePoco
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
}


public class Activity : BasePoco
{
    public ActivityType ActivityType { get; set; }

    [MaxLength(1000)]
    public string Description { get; set; }
}

现在有一种特殊类型的Activity称为数据捕获活动。 有两种类型:DataCaptureActivity和MasterDataCaptureActivity

public class DataCaptureActivityBase : Activity
{

    [MaxLength(100)]
    public string Title { get; set; }
}

派生类:

[Table("DataCaptureActivities")]
public class DataCaptureActivity : DataCaptureActivityBase
{
    public virtual DataCaptureActivityType DataCaptureActivityType { get; set; }
}

[Table("MasterDataCaptureActivities")]
public class MasterDataCaptureActivity : DataCaptureActivityBase
{
    public virtual string SomeOtherField{ get; set; }
}

问题出在创建迁移时,应该属于Title的列DataCaptureActivity实际上是Activity表的一部分。 请注意,DataCaptureActivityBase不应该是我的架构中的表。它仅用于保存公共参数DataCaptureActivities表及其继承类型。

我定位的架构是:

Activity
-------------------------------
Id  | ActivityType  | Description

DataCaptureActivity
--------------------------------
Id | Title

MasterDataCaptureActivity
--------------------------------
Id | Title | SomeOtherField

2 个答案:

答案 0 :(得分:1)

您的上下文与此类似

public DbSet<Activity> Activity { get; set; } 
public DbSet<DataCaptureActivity> DataCaptureActivities { get; set; }
public DbSet<MasterDataCaptureActivity> MasterDataCaptureActivities { get; set; }

您在概念上对EF说的是DataCaptureActivityActivityMasterDataCaptureActivityActivity。在数据库上,您将创建所有三个实体 使用此模型,语句

context.Activities.ToList();

检索所有Activities(三组联合)。

要对您的模型执行此操作,数据库上的EF将使用Discriminator创建Activity表。表结构将是这样(看1-1关系):

ExecuteNonQuery==========
CREATE TABLE [Activity] (
 [Id] int not null identity(1,1)
, [ActivityType] int not null
, [Description] text null
, [Title] varchar(100) null
, [Discriminator] varchar(128) not null
);
ALTER TABLE [Activity] ADD CONSTRAINT [PK_Activity_7ea65be8] PRIMARY KEY ([Id])
ExecuteNonQuery==========
CREATE TABLE [DataCaptureActivities] (
 [Id] int not null
, [DataCaptureActivityType] int not null
);
ALTER TABLE [DataCaptureActivities] ADD CONSTRAINT [PK_DataCaptureActivities_7ea65be8] PRIMARY KEY ([Id])
ExecuteNonQuery==========
CREATE TABLE [MasterDataCaptureActivities] (
 [Id] int not null
, [SomeOtherField] text null
);
ALTER TABLE [MasterDataCaptureActivities] ADD CONSTRAINT [PK_MasterDataCaptureActivities_7ea65be8] PRIMARY KEY ([Id])
ExecuteNonQuery==========
CREATE INDEX [IX_Id] ON [DataCaptureActivities] ([Id])
ExecuteNonQuery==========
CREATE INDEX [IX_Id] ON [MasterDataCaptureActivities] ([Id])
ExecuteNonQuery==========
ALTER TABLE [DataCaptureActivities] ADD CONSTRAINT [FK_DataCaptureActivities_Activity_Id] FOREIGN KEY ([Id]) REFERENCES [Activity] ([Id])
ExecuteNonQuery==========
ALTER TABLE [MasterDataCaptureActivities] ADD CONSTRAINT [FK_MasterDataCaptureActivities_Activity_Id] FOREIGN KEY ([Id]) REFERENCES [Activity] ([Id])

此外,这句话

using (var context = new Context(GetConnection()))
{
    context.DataCaptureActivities.Add(new DataCaptureActivity() {Description = "Description"});
    context.SaveChanges();
}

将生成此DML语句(2个插入语句!!!)

ExecuteDbDataReader==========
insert into [Activity]([ActivityType], [Description], [Title], [Discriminator])
values (@p0, @p1, null, @p2);
select [Id]
from [Activity]
where [Id] = @@identity
@p0 = 0
@p1 = Description
@p2 = DataCaptureActivity
ExecuteNonQuery==========
insert into [DataCaptureActivities]([Id], [DataCaptureActivityType])
values (@p0, @p1);

@p0 = 1
@p1 = 0

定位表格的解决方案

您需要更改模型,说明DataCaptureActivities和MasterDataCaptureActivities不是活动。

例如:

public abstract class BasePoco
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
}


public class BaseActivity : BasePoco
{
    public ActivityType ActivityType { get; set; }

    [MaxLength(1000)]
    public string Description { get; set; }
}

[Table("Activity")]
public class Activity : BaseActivity
{
}

public class DataCaptureActivityBase : BaseActivity
{

    [MaxLength(100)]
    public string Title { get; set; }
}

[Table("DataCaptureActivities")]
public class DataCaptureActivity : DataCaptureActivityBase
{
    public virtual DataCaptureActivityType DataCaptureActivityType { get; set; }
}

[Table("MasterDataCaptureActivities")]
public class MasterDataCaptureActivity : DataCaptureActivityBase
{
    public virtual string SomeOtherField { get; set; }
}

在这种情况下,表结构将是这个

ExecuteNonQuery==========
CREATE TABLE [Activity] (
 [Id] int not null identity(1,1)
, [ActivityType] int not null
, [Description] text null
);
ALTER TABLE [Activity] ADD CONSTRAINT [PK_Activity_2b28bd47] PRIMARY KEY ([Id])
ExecuteNonQuery==========
CREATE TABLE [DataCaptureActivities] (
 [Id] int not null identity(1,1)
, [DataCaptureActivityType] int not null
, [Title] varchar(100) null
, [ActivityType] int not null
, [Description] text null
);
ALTER TABLE [DataCaptureActivities] ADD CONSTRAINT [PK_DataCaptureActivities_2b28bd47] PRIMARY KEY ([Id])
ExecuteNonQuery==========
CREATE TABLE [MasterDataCaptureActivities] (
 [Id] int not null identity(1,1)
, [SomeOtherField] text null
, [Title] varchar(100) null
, [ActivityType] int not null
, [Description] text null
);
ALTER TABLE [MasterDataCaptureActivities] ADD CONSTRAINT [PK_MasterDataCaptureActivities_2b28bd47] PRIMARY KEY ([Id])

但在这种情况下,如果您想要在客户端上枚举所有ActivityBase您需要加入它们(Union)。

答案 1 :(得分:0)

尝试执行以下步骤。

  • 使用表属性标记活动类
  • 将Data DataCaptureActivityBase标记为abstract
  • 在OnModel中使用MapInheritedProperties();
  • 创建地图派生实体

希望这有帮助