0

EDIT - Quick summary

I realized that I had quite a bit of text, so here's a quick summary of the issue:

  • <many-to-any /> is unsupported by Fluent NHibernate
  • Want to split property mapping between XML and Fluent to map a <many-to-any /> relationship
  • Found out this is possible with named queries
  • When trying to use both XML and Fluent for my interface, I get an NHibernateDuplicateMappingException
  • When trying to use only XML for the interface and Fluent for my subclasses, the XML map makes it to the database, but the Fluent is ignored.

Since I have a ton of conventions defined, I would prefer not to only use XML for this class hierarchy.

Also, if anyone knows of an alternative solution to using many-to-any in Fluent, I'd be more than willing to give it a try.


EDIT - Full Question and Code Samples

I have two classes (we'll call them "Foo" and "Bar") that share a many-to-many relationship. Usually, mapping this with Fluent this would be as simple an throwing HasManyToMany(x => x.SomeProperty) into my class map; however, I've run into a problem with one of my interfaces.

For reference, here is a basic example setup of the objects:

public class Foo
{
    public virtual long ID { get; set; }
    public virtual string Name { get; set; }
    public virtual string Description { get; set; }
    public virtual IList<IBar> Bars { get; set; }
}

public interface IBar
{
    long ID { get; set; }
    IList<Foo> Foos { get; set; }
}

Since IBar is an interface that can be attached to pretty much any class, any "BarID" that would be referenced on an intermediate table could belong to any number of other tables. Since this is a "many-to-any" relationship, it is still unsupported by Fluent (yes, I know this is supported by NHibernate's mapping-by-code).

Luckily, NHibernate's xml mappings can still be easily used in a project that uses Fluent. Rather than defining the entire map in the *.hbm.xml file, though, I only want to map the <many-to-any />. The rest of it, I would like to keep in the Fluent map (basically, split the mapping out into two files).

I know this is possible with things like named queries and stored procedures, but I'm having a bit of trouble with using this pattern to define my relationship.

Here is the Fluent mapping for my Foo class as it is now:

public class FooMap : ClassMap<Foo>
{
    public FooMap()
    {
        Id(x => x.ID);
        Map(x => x.Name);
        Map(x => x.Description);
    }
}

And here the Foo.hbm.xml file:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="MyProject" namespace="MyProject.Entities">
    <class name="Foo" table="Foos"> 
        <id name="ID">      
            <generator class="identity" />
        </id>
        <bag name="Bars" table="FooBarRelationship">
            <key column="ID" />
            <many-to-any id-type="System.Int64" meta-type="System.String">
                <column name="BarID" />
                <column name="BarType" />
            </many-to-any>
        </bag>
    </class>
</hibernate-mapping>

On their own, both of these work fine. For example, if I'm just using the Fluent mapping, then my Foo table is generated with the three mapped columns. Similarly, if I just use the xml, then NHibernate creates a Foo table with an ID and a FooBarRelationship table, with both ID's, Foregin Keys, and the BarType column. Here's the problem, though: When I attempt to use both the xml and the Fluent mapping, I get an NHibernateDuplicateMappingException. Additionally, if I only use XML for the interface, but use Fluent for the subclasses, the Fluent maps are completely ignored (i.e., it acts as if I only had the xml).

I've done quite a bit of searching, but I haven't been able to find any information that might help. Is there anything I can do to either maps (or even the configuration) to get this to work?

Community
  • 1
  • 1
valverij
  • 4,871
  • 1
  • 22
  • 35

2 Answers2

0

I think you may end up having to put the entire Foo mapping (and sub classes) in the XML file. I believe you're right that you can combine fluent mappings and hbm mappings, but I don't believe you can do it when they are for the same entity, maybe this applies to subclasses too? It appears it's encountering a problem when a the root class(or interface)mapping is defined via different means than the sub class(es).

You might want to try doing as much of the mapping for that interface and it's sub classes in fluent, then run your app and export the config to an hbm file.

.Mappings(m =>
{
    m.FluentMappings.ExportTo(@"C:\")
}

From there trim it down to just the mappings for the interface and it's sub class, and then add your many-to-any mapping. I'm not going to pretend that it's a clean solution but I'm not familiar with the deep innards of nHibernate mapping to understand how it merges mapping from hbm files versus something like fluent or loquacious mappings.

I'm not sure what else you could try, short of switching to nHibernate's loquacious mapping (which I've been tempted to try as well were it not for their lack of support for where clauses on many to many mappings).

Nick Albrecht
  • 16,607
  • 10
  • 66
  • 101
  • Yeah, I've though about exporting the hbm for the entire hierarchy, I've just been trying to avoid it. If it were an option, I'd try switching to NHibernate's loquacious mapping. Maybe I can do something crazy with composite types. – valverij May 01 '13 at 16:53
0

I ran into this same issue, and came up with a semi-elegant solution. The same class cannot be mapped fluently and in an .hbm.xml file. However, you can map a subclass separately. My solution is to create an abstract FooBase class which is fluently mapped and contains everything except the features not supported by FluentNHibernate. Then, create a concrete Foo class which inherits FooBase, and map the Foo class (only the unsupported feature) in an .hbm.xml file.

The downside is it requires a slight modification to your domain structure, but IMO it's more elegant then trying to export and manipulate the XML generated by FluentNHibernate.

jonh
  • 233
  • 1
  • 10