How to have an entity inherit from another base entity and map to db using TPC with EF 4.2?

1.3k Views Asked by At

Say I have an entity model aggregate for Activity, like so:

public class Activity : Entity
{
    public int PersonId { get; set; }
    public virtual Person Person { get; set; }
    public int Number { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public virtual ICollection<ActivityTag> Tags { get; set; }
}

public class ActivityTag : Entity
{
    public int ActivityPersonId { get; set; }
    public int ActivityNumber { get; set; }
    public virtual Activity Activity { get; set; }
    public int Number { get; set; }
    public string Text { get; set; }
}

Forget about the relation between Activity and Person, but note the 1..* relation between Activity and ActivityTag. The fluent mapping looks more or less like this:

public class ActivityOrm : EntityTypeConfiguration<Activity>
{
    public ActivityOrm()
    {
        ToTable("Activity", "Activities");
        HasKey(p => new { p.PersonId, p.Number });
        HasRequired(d => d.Person)
            .WithMany()
            .HasForeignKey(d => d.PersonId)
            .WillCascadeOnDelete(true);
        HasMany(p => p.Tags)
            .WithRequired(d => d.Activity)
            .HasForeignKey(d => new { d.ActivityPersonId, d.ActivityNumber })
            .WillCascadeOnDelete(true);
        Property(p => p.Content).HasColumnType("ntext");
    }
}

public class ActivityTagOrm : EntityTypeConfiguration<ActivityTag>
{
    public ActivityTagOrm()
    {
        ToTable("ActivityTag", "Activities");
        HasKey(p => new { p.ActivityPersonId, p.ActivityNumber, p.Number });
        Property(p => p.Text).IsRequired().HasMaxLength(500);
    }
}

Given this, I want to introduce a new collection property to the Activity entity:

public ICollection<DraftedTag> DraftedTags { get; set; }

The DraftedTag entity should have the same exact properties and primary key as ActivityTag. The only thing that should be different is the table it is mapped to. I tried creating a class that derived from ActivityTag, like so:

public class DraftedTag : ActivityTag
{
}

public class DraftedTagOrm : EntityTypeConfiguration<DraftedTag>
{
    public DraftedTagOrm()
    {
        Map(m =>
        {
            m.MapInheritedProperties();
            m.ToTable("DraftedTag", "Activities");
        });
        HasKey(p => new { p.ActivityPersonId, p.ActivityNumber, p.Number });

    }
}

The DraftedTagOrm has been added to the modelBuilder.Configurations collection, but without even adding the foreign key association to Activity, I get the following exception:

The property 'ActivityPersonId' is not a declared property on type 'DraftedTag'. Verify that the property has not been explicitly excluded from the model by using the Ignore method or NotMappedAttribute data annotation. Make sure that it is a valid primitive property.

When I completely duplicate the code from the ActivityTag class and the ActivityTagOrm constructor into the respective DraftTag class / configuration constructor, then it works as expected -- I get two different tables with identical schemas, but different names. However each time I want to make a change to the ActivityTag class, I must make a corresponding change in the DraftTag class.

Is it possible to make this code DRYer by having DraftTag extend ActivityTag? If so, what would the EntityTypeConfiguration look like for DraftTag?

0

There are 0 best solutions below