4

I am trying to separate a large table into multiple discrete types.

I'm following the example here: http://weblogs.asp.net/manavi/archive/2011/04/24/associations-in-ef-4-1-code-first-part-4-table-splitting.aspx?CommentPosted=true#commentmessage

It's working for a primary type and a sub-type, but does not work when I employ multiple types. I received an error

The Entity types 'CampaginFeedback' and 'CampaignSurvey' cannot share table 'Campaign' because they are not int he same type hierarchy or do not have a valid one to one foreign key relationship with matching primary keys between them.

Here are simplified versions of my classes:

public class Campaign {
  [Key]
  public int CampaignId {get;set;}
  public string Name {get;set;}
  public virtual CampaignSurvey Survey {get;set;}
  public virtual CampaignFeedback Feedback {get;set;}
}

public class CampaignSurvey {
  [Key]
  public int CampaignId {get;set;}
  public string Question {get;set;}
  public string Answer {get;set;}
}

public class CampaignFeedback {
  [Key]
  public int CampaignId {get;set;}
  public string Feedback {get;set;}
}

protected override void OnModelCreating(DbModelBuilder modelBuilder) {
    modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<Campaign>().HasRequired(c => c.Survey).WithRequiredPrincipal();
    modelBuilder.Entity<Campaign>().HasRequired(c => c.Feedback).WithRequiredPrincipal();
    modelBuilder.Entity<Campaign>().ToTable("Campaign");
    modelBuilder.Entity<CampaignSurvey>().ToTable("Campaign");
    modelBuilder.Entity<CampaignFeedback>().ToTable("Campaign");
}
parleer
  • 1,220
  • 3
  • 12
  • 22

2 Answers2

4

Edit: Split table to more than two entities in code first is very problematic. It works without any problem when using EDMX.

To make it work you must ensure that each entity used to split table has valid one-to-one relation with all other entities used to split table. That also means spoiling your model with navigation properties and moreover ensuring that during save all navigation properties pointing to the same entity type reference the same instance (otherwise you will get exception during call to SaveChanges).

So the solution for your example should be something like:

public class Campaign {
  [Key]
  public int CampaignId {get;set;}
  public string Name {get;set;}
  public virtual CampaignSurvey Survey {get;set;}
  public virtual CampaignFeedback Feedback {get;set;}
}

public class CampaignSurvey {
  [Key]
  public int CampaignId {get;set;}
  public string Question {get;set;}
  public string Answer {get;set;}

  public virtual CampaignFeedback Feedback {get;set;}
}

public class CampaignFeedback {
  [Key]
  public int CampaignId {get;set;}
  public string Feedback {get;set;}
}

protected override void OnModelCreating(DbModelBuilder modelBuilder) {
    modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

    modelBuilder.Entity<Campaign>().HasRequired(c => c.Survey).WithRequiredPrincipal();
    modelBuilder.Entity<Campaign>().HasRequired(c => c.Feedback).WithRequiredPrincipal();
    modelBuilder.Entity<CampaignSurvey>().HasRequired(c => c.Feedback).WithRequiredPrincipal();

    modelBuilder.Entity<Campaign>().ToTable("Campaign");
    modelBuilder.Entity<CampaignSurvey>().ToTable("Campaign");
    modelBuilder.Entity<CampaignFeedback>().ToTable("Campaign");
}

I'm even not sure how this will work in the real scenario. You can find some other problems when using it.

Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
  • 2
    You're right! But, this is major bummer. I would think that splitting tables in some fashion ought to be supported without the hassle of making each entity track all the others. – parleer Dec 13 '11 at 18:26
0

Something I have found that works is to create a view and point your additional entities to that.

BlackICE
  • 8,816
  • 3
  • 53
  • 91