0

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?

danludwig
  • 46,965
  • 25
  • 159
  • 237
  • The key is already defined in your parent `ActivitTag` mapping so you should not define it again in derived mapping. The key must be same. What happens if you remove key mapping from `DraftedTag`? – Ladislav Mrnka Jun 04 '12 at 08:34
  • It then ends up with 2 relationships to Activity. One inherited by the parent, and another defined for the DraftedTag. – danludwig Jun 04 '12 at 13:40
  • But that is correct - it is what TPC demands. Database doesn't understand inheritance. If you want to have TPC hierarchy related to another table the relation must be created with every table in TPC hierarchy. – Ladislav Mrnka Jun 04 '12 at 14:03
  • So then, if I want Activity to have 2 separate collections -- 1 of ActivityTag and another of DraftedTag -- then the correct way to implement this is to make one *Tag entity extend the other? – danludwig Jun 04 '12 at 14:42

0 Answers0