Logo

NHibernate

The object-relational mapper for .NET

NHibernate Mapping - <many-to-any/>

<many-to-any/> is the logical extension of the <any/> feature that NHibernate has. At the time of this writing, if you do a Google search on <many-to-any/>, the first result is this post. It was written by me, in 2005, and contains absolutely zero useful information. Time to fix that.

Following up on the <any/> post, let us say that we need to map not a single heterogeneous association, but a multiple heterogeneous one, such as this:

In the database, it would appear as:

image

How can we map such a thing?

Well, that turn out to be pretty easy to do:

<set name="Payments" table="OrderPayments" cascade="all">
	<key column="OrderId"/>
	<many-to-any id-type="System.Int64"
			meta-type="System.String">
		<meta-value value="CreditCard"
			class="CreditCardPayment"/>
		<meta-value value="Wire"
			class="WirePayment"/>
		<column name="PaymentType" 
			not-null="true"/>
		<column name="PaymentId"
			not-null="true"/>
	</many-to-any>
</set>

Now, let us look at how we use this when we insert values:

using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{
	var order = new Order
	{
		Payments = new HashSet<IPayment>
        {
        	new CreditCardPayment
        	{
        		Amount = 6,
                CardNumber = "35434",
                IsSuccessful = true
        	},
            new WirePayment
            {
            	Amount = 3,
                BankAccountNumber = "25325",
                IsSuccessful = false
            }
        }
	};
	session.Save(order);
	tx.Commit();
}

This will produce some very interesting SQL:

image

image

image

image

image

I think that the SQL make it pretty clear what is going on here, so let us move to a more fascinating topic, what does NHibernate do when we read them?

Here is the code:

using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{
	var order = session.Get<Order>(1L);
	foreach (var payment in order.Payments)
	{
		Console.WriteLine(payment.Amount);
	}
	tx.Commit();
}

And the SQL:

image

image

image

image

As you can see, this is about as efficient as you can get. We load the order, we check what tables we need to check, and the we select from each of the tables that we found to get the actual values in the association.

True heterogeneous association, not used very often, but when you need it, you really love it when you do.


Posted Tue, 21 April 2009 06:52:00 PM by Ayende
Filed under: mapping

comments powered by Disqus
© NHibernate Community 2024