views:

30

answers:

1

Noob question.

I have this situation where I have these objects:

class Address
{      
   string Street;
   string City;
   ...
}

class User
{
   string UserID;
   Address BillingAddress;
   Address MailingAddress;
   ...
}

What is the proper way of storing this data using (fluent) nHibernate? I could use a separate Address table and create a reference, but they are 1:1 relationships so I don't really want to incur the overhead of a join. Ideally I would store this as a single flat record.

So, my question is, what is the proper way of storing an instance of class 'User' in such a way that it stores its contents and also the two addresses as a single record? My knowledge is failing me on how I can store this information in such a way that the two Address records get different column names (e.g. BillingAddress_Street and MailingAddress_Street, for example), and also how to read a record back into a User instance.

+2  A: 

These kinds of structures are referred to as a component. They're a normalized structure, and perfectly acceptable mechanism for representing data.

In Fluent NHibernate there are a couple of ways to map components. Firstly there's inline mappings, and then the external ComponentMap. I would recommend the latter in your situation, and in any scenario where you have a component that appears multiple times (either in the same entity, or across your domain).


Inline Components

To map a component, the simplest way is to use the Component method and specify how the component is composed using the body lambda.

  Component(x => x.BillingAddress, addr =>
  {
    addr.Map(x => x.Street);
    addr.Map(x => x.City);
  });

That's your address mapped. You'll need to repeat this for both addresses.


ComponentMap

The inline definition works fine for one-off components, but it can quickly become tiresome when you have multiple instances of the same component. ComponentMap solves this by extracting your component out into a self-contained, reusable, definition. You just use it exactly the same way as you do ClassMap.

public class AddressMap : ComponentMap<Address>
{
  public AddressMap()
  {
    Map(x => x.Street);
    Map(x => x.City);
  }
}

Then in your ClassMap, you just need to use the bodyless Component method; this instructs Fluent NHibernate to search for a ComponentMap matching the type of the property (if one isn't found, you'll know about it).

Component(x => x.BillingAddress);
Component(x => x.MailingAddress);

With the ComponentMap, column prefixes are automatically created as necessary based on the property that contains the component. If you need to customise this there's the ColumnPrefix method that's chained off the bodyless Component call.

Component(x => x.BillingAddress)
  .ColumnPrefix("Billing_");
James Gregory
Thanks, that is a great explanation! took me a while to figure out that the ComponentMap was not available in 1.0 RTM. But I did get it to work with a post RTM build. (Wasn't sure what you meant by 'external' in your post, you mean there is a way to add ComponentMap to the 1.0 RTM?
Will I Am
One other minor question -- not sure how NH decides to build the table, but it's creating: <billing columns><mailing columns><rest of user table> any way I can control it to create: <rest of user table><billing column><mailing column> ? At the very least I want my primary key from the User class to be the first column in the table (I'm anal that way! :)
Will I Am