views:

27

answers:

3

It seems like the following scenario shouldn't be uncommon, but I can't figure out how to handle it in FluenNHibernate:

public class Product: BaseEntity
{
    public Product()
    {
        Categories = new List<Category>();
    }

    public virtual IList<Category> Categories { get; set; }
    ...
}

public enum Categories
{
    Classic = 1,
    Modern = 2,
    Trendy = 3,
    ...
}

So, I need a ProductCategories table that allows me to map one product to many categories, but I don't think NHibernate will handle this unless I have an actual Categories class and a Categories table with a many-to-many relationship specified. There are a number of reasons this is not desirable, not the least of which is that it's overkill.

I'm using AutoMapper - any way I can override to make this work?

Thanks!

A: 

There are a few ways to do this, none of them as straightforward as you might expect. While NHibernate and Fluent NHibernate do quite well with a single enum, a collection is significantly more troublesom.

Here are a couple of approaches:

  1. Persist the collection to a single nvarchar(?) column by concatenating the members.
  2. Mark the enum with the Flags attribute and collapse the list as a bitmask (this will require just one integer column)

In either case, you can have NHibernate access a field that contains the "collapsed" values; the getters of the public properties will transform the collapsed values to collections. The getter of the collapsed value will transform the collection into a single string (1) or integer (2).

You'd have to map Product explicitly:

public class ProductMap : ClassMap<Product>
{
    public ProductMap()
    {
        Id(x => x.Id);

        Map(Reveal.Member<Product>("_categories"))
            .Access.Field();
    }
}

So although Product exposes an IList<Category>, NHibernate will only get and set the value of the _categories field;

Jay
A: 

At work, while it did not concern a collection of enum value, we created a custom type (by implementing IUserType to store a IDictionary<CultureInfo, string>.

We converted the dictionary into a xml document (XDocument) and we stored the data in an Xml column in Sql Server, although any string column could store the value.

You can see this site for information about implementing IUserType.

Pierre-Alain Vigeant
A: 

I had tried the concatenated string in another instance like this, but I really wanted something that didn't need to be transformed every time. As it turns out, I found a very similar question here: http://stackoverflow.com/questions/1423927/map-to-a-list-of-enums. As described there, this override works:

public void Override(AutoMapping<Product> mapping)
{
     mapping.HasMany(x => x.Categories).KeyColumn("ProductFk").Table("CategoriesProductsMap").Element("Category").AsBag();
}
sydneyos

related questions