Hello:
A TimeSheetActivity class has a collection of Allocations. An Allocation is a value object (immutable) looking something like this:
public class Allocation : ValueObject {
public virtual StaffMember StaffMember { get; private set; }
public virtual TimeSheetActivity Activity { get; private set; }
public virtual DateTime EventDate { get ... }
public virtual TimeQuantity TimeSpent { get ... }
}
The most convenient way to use this relationship in the domain is with an IDictionary, ie:
public virtual IEnumerable<Allocation> Allocations {
get { return _allocations.Values; } }
private readonly IDictionary<DateTime, Allocation> _allocations = new SortedList<DateTime, Allocation>();
I also need to be able to persist and fetch Allocations by StaffMember. If this was a data driven design, my concept is that there would be an Allocations table which would resolve the many-to-many relationship between Activities and StaffMembers:
table Allocations
ActivityID
StaffMemberID
EventDate
TimeQuantity
I'm having trouble visualizing the mappings. I'm trying to start with the TimeSheetActivity's Allocations, but I get the error below when I try to generate DDL:
NHibernate.MappingException: (XmlDocument)(3,6): XML validation error: The element 'class' in namespace 'urn:nhibernate-mapping-2.2' has invalid child element 'property' in namespace 'urn:nhibernate-mapping-2.2'. List of possible elements expected: 'meta, subselect, cache, synchronize, comment, tuplizer, id, composite-id' in namespace 'urn:nhibernate-mapping-2.2'.
I can't tell if I'm getting the error because:
A). I haven't yet mapped StaffMember to a collection of Allocations.
B). The mapping I have between Activity and Allocations is wrong.
C). All of the above
D). Other _____________________________________
AllocationMapping (in FNH)
public class AllocationMap : IAutoMappingOverride<Allocation>
{
public void Override(AutoMap<Allocation> mapping)
{
// these are both derived from the time period, so ignore
mapping.IgnoreProperty(x => x.TimeSpent);
mapping.IgnoreProperty(x => x.EventDate);
// TimePeriodUserType knows how to persist the time period start and end dates as DateTimes
mapping.Map(x => x.TimeSpentPeriod)
.ColumnNames.Add("PeriodStart", "PeriodEnd")
.SetAttribute("type", typeof(TimePeriodUserType).AssemblyQualifiedName);
mapping.References(x => x.Activity).WithForeignKey().FetchType.Join().Not.Nullable();
mapping.References(x => x.StaffMember).WithForeignKey().FetchType.Join().Not.Nullable();
}
}
Allocation mapping (generated hbm)
....
<property name="TimeSpentPeriod" type="..., ..., ...">
<column name="PeriodStart" />
<column name="PeriodEnd" />
</property>
<many-to-one foreign-key="FK_AllocationToStaffMember" fetch="join" not-null="true" name="StaffMember" column="StaffMemberID" />
<many-to-one foreign-key="FK_AllocationToActivity" fetch="join" not-null="true" name="Activity" column="TimeSheetActivityID" />
....
Activity mapping (FNH)
public class TimeSheetActivityMap : IAutoMappingOverride<TimeSheetActivity>
{
public void Override(AutoMap<TimeSheetActivity> mapping)
{
// this can be replaced by some id given by NHib via an inheritance type mapping??
mapping.IgnoreProperty(x => x.IdScheme);
// this is derived
mapping.IgnoreProperty(x => x.TotalTime);
// this is for client consumption only
mapping.IgnoreProperty(x => x.Allocations);
mapping.HasMany(x => x.Allocations)
.AsMap(x => x.EventDate)
.Cascade.All()
.Access.AsCamelCaseField(Prefix.Underscore)
.WithForeignKeyConstraintName("FK_ActivityAllocation");
}
}
ActivityMapping (generated hbm)
<set name="Allocations" cascade="all" access="field.camelcase-underscore">
<key foreign-key="FK_ActivityAllocation" column="TimeSheetActivityID" />
<one-to-many class="Smack.ConstructionAdmin.Domain.Model.TimeSheet.Allocation, ..." />
</set>
This is a complicated mapping for my level of experience with NHibernate, so I'd appreciate any help, questions, or criticisms on the mapping technique, the modeling concept, or my approach to working through this.
Cheers, Berryl