"Association references unmapped class"
I'm trying to use the Fluent NHibernace AutoMapper to map my entities, but I'm running into a problem...
ClassA has a reference to ClassB. Classes ClassC and ClassD both inherit from ClassB.
I would like for ClassB to be abstract so that only instances of ClassC and ClassD (the concrete classes) can be created.
When I make ClassB abstract, however, I get an error on the Fluently.Configure() statement complaining that "Association references unmapped class: ClassB". I've tried a few other things including IgnoreBase and changing ClassA to reference an interface, IClassB, which is implemented by ClassC and ClassD. So far, nothing has worked and I always get the same error message.
There ought to be a way to map using a table per concrete class (classes ClassC and ClassD) and still allow ClassA to hold a reference to the supertype (ClassB) since the referenced object might be of either ClassC or ClassD. This makes sense from an object viewpoint. I just can't get the mapping to work.
Any ideas would be greatly appreciated!
Comments are currently closed for this discussion. You can start a new one.
Support Staff 2 Posted by Hudson Akridge on 02 Mar, 2010 05:12 PM
This should be working without the IgnoreBase() call. Just to make sure you're doing everything correctly:
http://wiki.fluentnhibernate.org/Auto_mapping#Ignoring_base-types
See if you can call .ExportTo() and get the XML out that FNH generates (I believe you can do it without calling .Configure(), but maybe not). That should help us understand what's going on here. It should work, this seems like a pretty simple setup.
3 Posted by MylesRip on 02 Mar, 2010 05:50 PM
It seems that ExportTo is only available after m.FluentMappings, but I'm using m.AutoMappings. Is there a way to export when using the automapper? Here is my complete configuration statement:
Support Staff 4 Posted by James Gregory on 02 Mar, 2010 06:11 PM
ExportTo
should be available fromAutoMappings
too, it's certainly there in the code.5 Posted by MylesRip on 02 Mar, 2010 07:05 PM
I was trying to put it in all of the wrong places... Attached are the relevant hbm files. "Item" has been renamed to "AssessedItem" and is the class I wanted to be abstract. Please let me know if there is any additional information I can provide. Thanks!
6 Posted by MylesRip on 03 Mar, 2010 05:25 PM
Some more information...
I exported the hbm files for 3 scenarios:
1) Non-abstract AssessedItem entity.
2) Abstract AssessedItem entity.
3) Non-abstract AssessedItem entity and IgnoreBase()
The exported hbm files for options 2 & 3 are exactly the same. That is, making the entity abstract has the same effect as telling FNH to ignore it as a base class.
Here are the differences between option 1 and the other options:
Option 1 creates an hbm file for AssessedItem which includes joined sub-classes for the types that inherit from it.
Options 2 and 3 create separate hbm files for each of the types that inherit from AssessedItem, but no hbm file for AssessedItem itself. Each of the hbm files for the types that inherit from AssessedItem include the fields inherited from AssessedItem.
There are a couple of other classes that hold references to AssessedItem where I intend the various subtypes to be treated polymorphically. This is where I run into a problem. Options 2 and 3 don't create a database table for AssessedItem and I get the "Association references unmapped class: AssessedItem" error.
FNH currently includes SubclassStrategy options for "Subclass" (a.k.a. table per class hierarchy) and "JoinedSubclass" (a.k.a. table per class). The third subclass strategy, table per concrete class, can be achieved by chaining .IgnoreBase calls as needed. In order to handle these classes polymorphically when using this third strategy, I believe that support for NHibernate's "union-subclass" would be required. Unfortunately, FNH doesn't seem to currently offer a UnionSubclass Subclass strategy.
Does this make sense or am I missing something?
7 Posted by MylesRip on 04 Mar, 2010 06:41 PM
For the time being, I'm just going to avoid trying to use the "table per concrete class" approach as it doesn't seem to lend itself very easily to polymorphism.
I had been wanting to use that approach mainly because it would have led to a fairly easy-to-understand database schema (for colleagues who prefer to look at ERDs rather than class diagrams) and also for ease in reporting against the database. In addition, it would have been nice to be able to mark superclasses as abstract in the domain model to make sure that only the subclasses can be instantiated.
The "table per class hierarchy" approach doesn't look attractive to me unless there are only a small number of types in the hierarchy and the differences between the types are small.
This leaves me with the "table per class" approach. This makes the ERD diagram look very similar to the class diagram, but it makes for some very intricate, verbose SQL involving lots of inserts to different tables when saving a single object and lots of joins when retrieving an object. I'm not sure how the database-centric guys will take to it. :-) I'm also a little concerned about using reporting engines that go against the database because the intricate, verbose SQL statements mentioned above would likely need to be recreated as views in the database and I was hoping to avoid that if possible.
I'd really be interested in hearing other people's thoughts on this. :-)
Support Staff 8 Posted by Paul Batum on 07 Mar, 2010 11:14 AM
I'm not sure if I'm following the problem exactly, but my fluent nhibernate test bed repository has a branch that demonstrates an automapped polymorphic list, with an abstract base class. Its really stripped down so it should be straightforward to follow - maybe it will help shed some light on the matter?
http://github.com/paulbatum/Fluent-NH-Test-Bed/tree/automapped-poly...
Unless you're comfortable with git, the best bet would be the download source button on that page.
9 Posted by MylesRip on 08 Mar, 2010 06:47 PM
Hi Paul,
Thanks for responding! I looked at your domain model in which you have the following:
IList<Debt>
.I noticed that your FNH configuration statement includes the following:
.IncludeBase<Debt>()
This causes the Debt class to be mapped to a table, which solves one of my problems because it allows the Debt class to be defined as abstract and still be used as the type for a generic collection held by another object. (Thanks, Paul!) This is good because, even though I still have more tables in the database than I'd like, I can at least enforce the fact that "Debt" can't be instantiated directly in the domain layer.
If you remove the IncludeBase statement in your solution, you will get the same error that I was getting.
If you wanted to use a "table per concrete class" approach, then there would be no database table for the Debt class and you would need to map your classes with something like:
<class name="Debt">
</class>
The above is described in section 8.1.5 of the NHibernate 2.1.0 documentation. This approach doesn't seem to be currently supported in FNH.
I have a fairly deep hierarchy and I'd like to cut down on the number of tables (without going all the way to a single table per hierarchy). Ideally, I'd like to switch approaches, partway down the hierarchy, to a "table per sub-hierarchy" approach.
Hmm... Maybe another way of getting rid of the individual tables for the higher level classes would be to use a "table per hierarchy" approach for the upper portion of the hierarchy and then break out to a separate table that also uses a "table per hierarchy" approach for the longest sub-branch of the hierarchy. This would significantly reduce the number of extra, seldom-used fields in each table because most of the additional fields come into the hierarchy at a single point in the sub-hierarchy. That would be a good place to break out a separate table. I'll have to play around with that a bit.
Thanks again for your response!
Support Staff 10 Posted by Paul Batum on 11 Mar, 2010 04:58 AM
Thanks for your explanation Myles, I understand now. It is a shame we don't support union subclass because I can see how it would be useful. I suspect we don't support it simply because nobody has needed it enough yet. Have you thought about attempting this yourself?
11 Posted by MylesRip on 11 Mar, 2010 03:40 PM
Unfortunately I'm currently under a deadline and the combined learning curves of NH, FNH, RIA Services and Silverlight (all at the same time!) are taking their toll on my productive time. (But I'm having lots of fun!)
By the way, although there are understandably a couple of gaps in functionality here and there, I know it's still a young project and I have to say I'm really impressed with what I've seen from FNH so far! Not having to manually maintain dozens of hbm files will make this project significantly easier to maintain during development and in the future. Putting a fluent interface on NH was a brilliant idea! Kudos to all involved!
James Gregory closed this discussion on 24 Mar, 2010 08:57 AM.