Does this inheritance design belong in the database?
- by Berryl
=== CLARIFICATION ====
The 'answers' older than March are not answers to the question in this post!
Hello
In my domain I need to track allocations of time spent on Activities by resources. There are two general types of Activities of interest - ones base on a Project and ones based on an Account.
The notion of Project and Account have other features totally unrelated to both each other and capturing allocations of time, and each is modeled as a table in the database.
For a given Allocation of time however, it makes sense to not care whether the allocation was made to either a Project or an Account, so an ActivityBase class abstracts away the difference. An ActivityBase is either a ProjectActivity or an AccountingActivity (object model is below).
Back to the database though, there is no direct value in having tables for ProjectActivity and AccountingActivity.
BUT the Allocation table needs to store something in the column for it's ActivityBase. Should that something be the Id of the Project / Account or a reference to tables for ProjectActivity / Accounting? How would the mapping look?
=== Current Db Mapping (Fluent) ====
Below is how the mapping currently looks:
public class ActivityBaseMap : IAutoMappingOverride<ActivityBase>
{
public void Override(AutoMapping<ActivityBase> mapping)
{
//mapping.IgnoreProperty(x => x.BusinessId);
//mapping.IgnoreProperty(x => x.Description);
//mapping.IgnoreProperty(x => x.TotalTime);
mapping.IgnoreProperty(x => x.UniqueId);
}
}
public class AccountingActivityMap : SubclassMap<AccountingActivity>
{
public void Override(AutoMapping<AccountingActivity> mapping)
{
mapping.References(x => x.Account);
}
}
public class ProjectActivityMap : SubclassMap<ProjectActivity>
{
public void Override(AutoMapping<ProjectActivity> mapping)
{
mapping.References(x => x.Project);
}
}
There are two odd smells here. Firstly, the inheritance chain adds nothing in the way of properties - it simply adapts Projects and Accounts into a common interface so that either can be used in an Allocation. Secondly, the properties in the ActivityBase interface are redundant to keep in the db, since that information is available in Projects and Accounts.
Cheers,
Berryl
==== Domain =====
public class Allocation : Entity
{
...
public virtual ActivityBase Activity { get; private set; }
...
}
public abstract class ActivityBase : Entity
{
public virtual string BusinessId { get; protected set; }
public virtual string Description { get; protected set; }
public virtual ICollection<Allocation> Allocations { get { return _allocations.Values; } }
public virtual TimeQuantity TotalTime {
get { return TimeQuantity.Hours(Allocations.Sum(x => x.TimeSpent.Amount)); }
}
}
public class ProjectActivity : ActivityBase
{
public virtual Project Project { get; private set; }
public ProjectActivity(Project project) {
BusinessId = project.Code.ToString();
Description = project.Description;
Project = project;
}
}