Duplicate subclass mapping created when using IAutoMappingOverride<T>

200 views
Skip to first unread message

Jimit

unread,
Feb 19, 2009, 11:01:45 AM2/19/09
to Fluent NHibernate
It seems JoinedSubClass is being called for derived entities
regardless of any overrides that have been made in
IAutoMappingOverride<T>. AutoMapper.MergeMap calls JoinedSubClass
whenever it discovers an inheritance relationship. This works fine if
your mapping override you actually do declare a joined subclass but if
you've used a SubClass with discriminator column instead your mapping
will end up with the joined subclass as well as the subclass mapping:

This mapping override:

public class LegAutoMappingOverride : IAutoMappingOverride<Leg>
{

#region IAutoMappingOverride<Leg> Members

public void Override(FluentNHibernate.AutoMap.AutoMap<Leg>
mapping)
{
mapping.References(l => l.Origin)
.PropertyRef(o => o.OutgoingLegs);
mapping.HasOne(leg => leg.Load)
.PropertyRef(load => load.Leg)
.WithForeignKey();
mapping.HasMany(l => l.DependentLegs)
.Inverse()
.Cascade.SaveUpdate()
.LazyLoad().AsSet();
mapping.References(leg => leg.Trip)
.PropertyRef(trip => trip.Legs)
.Not.Nullable()
.WithForeignKey();
mapping.DiscriminateSubClassesOnColumn<byte>("Type")
.SubClass<TrunkLeg>((byte)LegType.Trunk,
trunkLeg => trunkLeg.References(t
=> t.Destination)
.PropertyRef(o =>
o.IncomingLegs))
.SubClass<DistributionLeg>((byte)LegType.Distribution,
destLeg => destLeg.HasMany
(d => d.Drops)
.AsSet().Cascade.All());
}

#endregion
}

produces the following mapping:

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-
lazy="true" assembly="Core.Domain" namespace="Core.Domain.Entities">
<class name="Leg" table="Leg" xmlns="urn:nhibernate-mapping-2.2">
<cache usage="read-write" />
<id name="Id" column="Id" type="Int32" access="nosetter.pascalcase-
underscore">
<generator class="native" />
</id>
<discriminator column="Type" type="Byte" />
<property name="Status"
type="FluentNHibernate.Mapping.GenericEnumMapper`1
[[Core.Domain.Entities.LegStatus, Core.Domain, Version=0.1.3337.26501,
Culture=neutral, PublicKeyToken=94dc7dc697cfcfc0]], FluentNHibernate,
Version=0.1.0.0, Culture=neutral, PublicKeyToken=8aa435e3cb308880">
<column name="Status" sql-type="string" />
</property>
<property name="DispatchTime" type="DateTime">
<column name="DispatchTime" />
</property>
<property name="LastModifiedBy" length="100">
<column name="LastModifiedBy" />
</property>
<property name="LegNo" type="Int32">
<column name="LegNo" />
</property>
<many-to-one name="Vehicle" column="VehicleId" />
<set name="DependentLegs" inverse="true" cascade="save-update"
lazy="true">
<key column="LegID" />
<one-to-many class="Core.Domain.Entities.Leg, Core.Domain,
Version=0.1.3337.26501, Culture=neutral,
PublicKeyToken=94dc7dc697cfcfc0" />
</set>
<many-to-one property-ref="Legs" not-null="true" foreign-
key="FK_LegToTrip" name="Trip" column="TripId" />
<one-to-one property-ref="Leg" foreign-key="FK_LegToLoad"
name="Load" class="Core.Domain.Entities.Load, Core.Domain,
Version=0.1.3337.26501, Culture=neutral,
PublicKeyToken=94dc7dc697cfcfc0" />
<many-to-one property-ref="OutgoingLegs" name="Origin"
column="OriginId" />
<joined-subclass name="Core.Domain.Entities.TrunkLeg, Core.Domain,
Version=0.1.3337.26501, Culture=neutral,
PublicKeyToken=94dc7dc697cfcfc0">
<key column="LegId" />
<property name="TimeOfArrival" type="DateTime">
<column name="TimeOfArrival" />
</property>
<property name="EstimatedTimeOfArrival" type="DateTime">
<column name="EstimatedTimeOfArrival" />
</property>
<many-to-one name="Destination" column="DestinationId" />
</joined-subclass>
<joined-subclass name="Core.Domain.Entities.DistributionLeg,
Core.Domain, Version=0.1.3337.26501, Culture=neutral,
PublicKeyToken=94dc7dc697cfcfc0">
<key column="LegId" />
<bag name="Drops" cascade="save-update">
<key column="DistributionLegID" />
<one-to-many class="Core.Domain.Entities.Drop, Core.Domain,
Version=0.1.3337.26501, Culture=neutral,
PublicKeyToken=94dc7dc697cfcfc0" />
</bag>
</joined-subclass>
<subclass name="Core.Domain.Entities.TrunkLeg, Core.Domain,
Version=0.1.3337.26501, Culture=neutral,
PublicKeyToken=94dc7dc697cfcfc0" discriminator-value="2">
<many-to-one property-ref="IncomingLegs" name="Destination"
column="DestinationId" />
</subclass>
<subclass name="Core.Domain.Entities.DistributionLeg, Core.Domain,
Version=0.1.3337.26501, Culture=neutral,
PublicKeyToken=94dc7dc697cfcfc0" discriminator-value="1">
<set name="Drops" cascade="save-update">
<key column="DistributionLegID" />
<one-to-many class="Core.Domain.Entities.Drop, Core.Domain,
Version=0.1.3337.26501, Culture=neutral,
PublicKeyToken=94dc7dc697cfcfc0" />
</set>
</subclass>
</class>
</hibernate-mapping>

As you can see the subclasses DistributionLeg and TrunkLeg are mapped
twice and only one of them (the table-per-hierarchy using Subclass
with discriminator) is actually defined in the mapping override.

Jimit

unread,
Feb 19, 2009, 12:32:57 PM2/19/09
to Fluent NHibernate
I've fixed this problem by modifying AutoMapper.MergeMap<T> to check
for the existence of any SubClassPart<,,> for that derived type in the
AutoMap<T>.Parts of the type being mapped. I'll submit a patch for
that in a minute. More urgently though, fixing that uncovered another
problem:
Whereas I'd been getting errors on schema validation about the
existence of the subclass element in the class mapping due to the
joinedsubclass element being created... now the schema validation
succeeds and I get an error further down the chain when i try to do a
schema export:

PersistenceTests.Can_Map_Orders_To_Database :
FailedSystem.InvalidCastException: Unable to cast object of type
'NHibernate.Mapping.Bag' to type 'NHibernate.Mapping.SimpleValue'.
at NHibernate.Cfg.Configuration.SecondPassCompile()
at NHibernate.Cfg.Configuration.GenerateDropSchemaScript(Dialect
dialect)
at NHibernate.Tool.hbm2ddl.SchemaExport..ctor(Configuration cfg,
IDictionary`2 connectionProperties)
at NHibernate.Tool.hbm2ddl.SchemaExport..ctor(Configuration cfg)
at
Core.Infrastructure.Data.NHibernate.Tests.PersistenceTests.<SetUp>b__0
(Configuration cfg) in PersistenceTests.cs: line 25
at FluentNHibernate.Cfg.FluentConfiguration.BuildSessionFactory() in
FluentConfiguration.cs: line 97
FluentNHibernate.Cfg.FluentConfigurationException: An invalid or
incomplete configuration was used while creating a SessionFactory.
Check PotentialReasons collection, and InnerException for more detail.


at FluentNHibernate.Cfg.FluentConfiguration.BuildSessionFactory() in
FluentConfiguration.cs: line 103
at Core.Infrastructure.Data.NHibernate.Tests.PersistenceTests.SetUp()
in PersistenceTests.cs: line 22

This seems to be coming from within the core NHibernate dll and since
I have no familiarity with Nhibernate prior to FNH I'm totally stumped
and have no idea how to proceed. I'm exporting the schema to an in-
memory SQLite database btw. Should I be posting this on the nhusers
forum?
Reply all
Reply to author
Forward
0 new messages