2017-07-05 1 views
2

J'ai un heriarchy de inheriance à plusieurs niveaux composé des classes suivantes:EF Code de premiers numéros inheritence multi-niveaux

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

Maintenant, il y a un type d'activité qui est appelée une activité de saisie de données. Ce qui est de deux types: DataCaptureActivity et MasterDataCaptureActivity

public class DataCaptureActivityBase : Activity 
{ 

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

classes dérivées:

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

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

Le problème est sur la création d'une migration, la colonne Title qui devrait être une partie de DataCaptureActivity est en réalité à venir comme une partie de la table Activity. Veuillez noter que DataCaptureActivityBase ne devrait pas être une table dans mon schéma. Il est juste pour la table commune des paramètres DataCaptureActivities et ses types hérités.

Le schéma Je suis le ciblage est:

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

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

MasterDataCaptureActivity 
-------------------------------- 
Id | Title | SomeOtherField 
+1

Quels niveaux de la hiérarchie d'héritage mappez-vous à la base de données (en incluant les propriétés DbSet dans votre DbContext)? Parfois, il est logique de ne cartographier que les niveaux les plus bas dans la base de données. –

+0

Comme David l'a dit, le DbContext est très important ici. Si vous exposez DbSet , le titre doit être sur DataCaptureActivityBase. – bubi

+0

@ DavidBrowne-Microsoft, @bubi Voir le schéma attendu, Le problème est que 'Title' est ajouté à la table' Activity' au lieu des deux tables dérivées – SJMan

Répondre

1

Votre contexte est similaire à ce

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

Ce que vous dites sur le plan conceptuel à EF est que DataCaptureActivity est un Activity et que MasterDataCaptureActivity est un Activity. Sur la base de données, vous créez toutes les trois entités.
Avec ce modèle, la déclaration

context.Activities.ToList(); 

récupérer toute l'Activities (l'union des trois ensembles). Pour le faire avec votre modèle, EF sur la base de données va créer la table d'activité avec un discriminateur. Les structures de table seront ce (regardez 1-1 relations):

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]) 

En outre, cette déclaration

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

générera ce déclarations DML (2 états d'insertion !!!)

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 

La solution pour cibler vos tables

Vous devez modifier votre modèle en indiquant que DataCaptureActivities et MasterDataCaptureActivities ne sont pas des activités.

Par exemple:

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

Dans ce cas, les structures de tables seront ce

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]) 

Mais dans ce cas, si vous voulez enum tous les ActivityBase dont vous avez besoin de les rejoindre (Union) sur le client.

0

Essayez de faire les étapes ci-dessous.

  • classe Activité Mark avec un tableau d'attributs
  • Mark DataCaptureActivityBase comme abstract
  • Dans OnModelCreating Carte Entités dérivées avec MapInheritedProperties();

Hope this helps