EDIT: Added HBM mapping at the end of the post.
I have a rather large class library, with inheritance involved. I'm using Fluent NHibernate to map the classes to MS SQL 2008 to host this in Azure.
I'm fairly sure the mappings are correct. We use a Discriminator Value to differentiate the classes on column (not on table). However, whenever I try to generate the mappings, I get an error that one of the class/entity is a duplicate.
Duplicate class/entity mapping FolkeLib.MMOBash.Bash
This happens here:
private static ISessionFactory CreateSessionFactory()
{
return Fluently.Configure()
.Database(
MsSqlConfiguration.MsSql2008.Dialect("NHibernate.Dialect.MsSql2008Dialect")
.ConnectionString(c =>
c.FromConnectionStringWithKey("FolkeConnString"))
.ShowSql())
.Mappings(m =>
m.FluentMappings.AddFromAssemblyOf<Account>())
.ExposeConfiguration(cfg =>
new SchemaUpdate(cfg).Execute(false, true))
.Diagnostics(diag => diag.Enable().OutputToConsole())
.BuildSessionFactory();
}
The class hierarchy is something like this
- Message
- Comment
- ForumMessage
- Article
- Image
- Bash
- Image
- Article
Bash inherits from Image, which Inherits from Article, and so on. They all have a different discriminator value. Message mappings are defined like this:
public class MessageMap : ClassMap<Message>
{
MessageMap()
{
Id(x => x.Id);
DiscriminateSubClassesOnColumn("MessageType").SqlType("int32");
Map(x => x.CreationDate).Index("ArticleCreationDate");
Map(x => x.ModificationDate);
Map(x => x.LastChildCreationDate);
References(x => x.Author);
References(x => x.RootMessage).Nullable(); ;
References(x => x.ParentMessage).Nullable(); ;
}
}
(there are more properties but they are irrelevant I think). Note that RootMessage and ParentMessages are themselves of the type "Message." Could this be the root cause?
Bash mappings are like this:
public class BashMap : SubclassMap<Bash>
{
BashMap()
{
DiscriminatorValue(5);
Map(x => x.Game);
Map(x => x.Language);
References(x => x.ApprovedBy);
}
}
I have spent hours on this and I have no idea why I get a Duplicate class/entity mapping error.
EDIT: Troubleshooting update.
Following suggestions below I added this bit of code:
public ActionResult Zogzog()
{
List<string> types = new List<string>();
foreach (var module in typeof(Account).Assembly.GetModules())
{
foreach (var type in module.GetTypes())
{
if (typeof(IMappingProvider).IsAssignableFrom(type))
{
types.Add(type.ToString());
}
}
}
ViewBag.Types = types;
return View();
}
The output of the view is this:
FolkeLib.Calendar.EventRoleMap
FolkeLib.Calendar.LocationMap
FolkeLib.Calendar.RegistrationMap
FolkeLib.Calendar.RoleMap
FolkeLib.Domain.AccountMap
FolkeLib.Domain.AccountBanMap
FolkeLib.Domain.CommunityMap
FolkeLib.Domain.ContactEntryMap
FolkeLib.Domain.ContactTypeMap
FolkeLib.Domain.ForumMap
FolkeLib.Domain.ReadMessageMap
FolkeLib.Domain.RssFeedMap
FolkeLib.Domain.SkinMap
FolkeLib.Domain.GroupMap
FolkeLib.Domain.LanguageMap
FolkeLib.Domain.MenuMap
FolkeLib.Domain.MenuItemMap
FolkeLib.Domain.MessageMap
FolkeLib.Domain.PollMap
FolkeLib.Domain.PollAnswerMap
FolkeLib.Domain.PollVoteMap
FolkeLib.Domain.QuoteMap
FolkeLib.Domain.MessageReportMap
FolkeLib.Game.CharacterMap
FolkeLib.Domain.RssChannelMap
FolkeLib.Domain.SiteMap
FolkeLib.Domain.SiteApplicationModuleMap
FolkeLib.Domain.StaticTextMap
FolkeLib.Domain.TagMap
FolkeLib.Domain.VoteMap
I don't seem to have duplicates, however none of the children of Message seem to appear. I'm not sure if that is normal (they are of type SubclassMap, what is shown here is of type ClassMap) or not but this was asked in the comments.
EDIT: This is the Message.hbm.xml file generated by Fluent. As we can see, some classes (Bash, Article, ...) are shown several time as subclasses, sometimes with different discriminator values!
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class xmlns="urn:nhibernate-mapping-2.2" name="FolkeLib.Domain.Message, FolkeLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="`Message`">
<id name="Id" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="Id" />
<generator class="identity" />
</id>
<discriminator type="String">
<column name="MessageType" sql-type="int32" />
</discriminator>
<property name="CreationDate" type="System.DateTime, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="CreationDate" index="ArticleCreationDate" />
</property>
<property name="ModificationDate" type="System.DateTime, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="ModificationDate" />
</property>
<property name="LastChildCreationDate" type="System.DateTime, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="LastChildCreationDate" />
</property>
<property name="Text" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="Text" />
</property>
<property name="Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="Locked" />
</property>
<property name="Score" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="Score" />
</property>
<property name="Hidden" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="Hidden" />
</property>
<property name="Deleted" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="Deleted" />
</property>
<property name="AuthorIp" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="AuthorIp" />
</property>
<property name="PublicationDate" type="System.DateTime, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="PublicationDate" />
</property>
<many-to-one class="FolkeLib.Domain.Account, FolkeLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="Author">
<column name="Author_id" />
</many-to-one>
<many-to-one class="FolkeLib.Domain.Account, FolkeLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="Locker">
<column name="Locker_id" not-null="false" />
</many-to-one>
<many-to-one class="FolkeLib.Domain.Message, FolkeLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="RootMessage">
<column name="RootMessage_id" not-null="false" />
</many-to-one>
<many-to-one class="FolkeLib.Domain.Message, FolkeLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="ParentMessage">
<column name="ParentMessage_id" not-null="false" />
</many-to-one>
<many-to-one class="FolkeLib.Domain.Site, FolkeLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="Site">
<column name="Site_id" not-null="true" />
</many-to-one>
<many-to-one class="FolkeLib.Domain.Forum, FolkeLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="Forum">
<column name="Forum_id" />
</many-to-one>
<many-to-one class="FolkeLib.Domain.Account, FolkeLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="DeletedBy">
<column name="DeletedBy_id" />
</many-to-one>
<subclass name="FolkeLib.Domain.Comment, FolkeLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" discriminator-value="2" />
<subclass name="FolkeLib.Domain.ForumMessage, FolkeLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" discriminator-value="3">
<property name="Title" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="Title" />
</property>
<subclass name="FolkeLib.Calendar.Event, FolkeLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" discriminator-value="6">
<bag lazy="true" name="RoleSet" table="EventEventRole">
<key>
<column name="Event_id" />
</key>
<many-to-many class="FolkeLib.Calendar.EventRole, FolkeLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<column name="EventRole_id" />
</many-to-many>
</bag>
<property name="Duration" type="System.TimeSpan, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="Duration" />
</property>
<property name="RecurringDays" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="RecurringDays" />
</property>
<property name="FirstTime" type="System.DateTime, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="FirstTime" />
</property>
<property name="LastTime" type="System.DateTime, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="LastTime" />
</property>
<many-to-one class="FolkeLib.Calendar.Location, FolkeLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="Location">
<column name="Location_id" />
</many-to-one>
</subclass>
<subclass name="FolkeLib.Domain.Article, FolkeLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" discriminator-value="1">
<subclass name="FolkeLib.Domain.Image, FolkeLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" discriminator-value="1">
<property name="Name" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="Name" />
</property>
<property name="Extension" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="Extension" />
</property>
<property name="Public" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="Public" />
</property>
<property name="ForAdults" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="ForAdults" />
</property>
<subclass name="FolkeLib.MMOBash.Bash, FolkeLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" discriminator-value="5">
<property name="Game" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="Game" />
</property>
<property name="Language" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="Language" />
</property>
<many-to-one class="FolkeLib.Domain.Account, FolkeLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="ApprovedBy">
<column name="ApprovedBy_id" />
</many-to-one>
</subclass>
</subclass>
</subclass>
<subclass name="FolkeLib.Domain.Article, FolkeLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" discriminator-value="4">
<bag name="TagSet" table="TagToArticle">
<key>
<column name="Article_id" />
</key>
<many-to-many class="FolkeLib.Domain.Tag, FolkeLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<column name="Tag_id" />
</many-to-many>
</bag>
<bag name="ImageSet" table="ImageToArticle">
<key>
<column name="Article_id" />
</key>
<many-to-many class="FolkeLib.Domain.Image, FolkeLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<column name="Image_id" />
</many-to-many>
</bag>
<property name="ExtraText" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="ExtraText" />
</property>
<subclass name="FolkeLib.Domain.Image, FolkeLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" discriminator-value="1">
<property name="Name" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="Name" />
</property>
<property name="Extension" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="Extension" />
</property>
<property name="Public" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="Public" />
</property>
<property name="ForAdults" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="ForAdults" />
</property>
<subclass name="FolkeLib.MMOBash.Bash, FolkeLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" discriminator-value="5">
<property name="Game" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="Game" />
</property>
<property name="Language" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="Language" />
</property>
<many-to-one class="FolkeLib.Domain.Account, FolkeLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="ApprovedBy">
<column name="ApprovedBy_id" />
</many-to-one>
</subclass>
</subclass>
</subclass>
</subclass>
</class>
</hibernate-mapping>
typeof(IMappingProvider).IsAssignableFrom(type)to see if the mappings are duplicated somehow? - FiroIIndeterminateSubclassMappingProvider. Another unlikely cause could be that two subclasses inherit fromSubclassMap<Bash>and since they have the same properties it doesnt give compilererrors - Firo