Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to automap a collection of components with Fluent NHibernate?

All of my entities and value objects implement marker interfaces IEntity and IValueObject. I have set them up to be treated as components like so:

public override bool IsComponent(Type type)
{
    return typeof(IValueObject).IsAssignableFrom(type);
}

public override bool ShouldMap(Type type)
{
    return typeof(IEntity).IsAssignableFrom(type) || typeof(IValueObject).IsAssignableFrom(type);
}

Unfortunately, this does not seem to allow entities that have collections of value objects to be automapped as component collections. For example:

public class MyEntity : IEntity
{
    public IList<MyValueObject> Objects { get; set; }
}

public class MyValueObject : IValueObject
{
    public string Name { get; set; }
    public string Value { get; set; }
}

Is there any way to define a convention such that, any time an IEntity has an IList of a type that implements IValueObject, it gets mapped as if I had specified:

HasMany(x => x.Objects)
    .Component(x => { 
        x.Map(m => m.Name); 
        x.Map(m => m.Value); 
    });

What I don't want to do is have to manually do these overrides for every class and write out each property for the value object again and again.

like image 820
Joran Avatar asked Jan 26 '11 22:01

Joran


1 Answers

  1. Create a new class that inherits from HasManyStep (FluentNHibernate.Automapping.Steps).
  2. Override the ShouldMap() method with something like :

    return base.ShouldMap(member) && IsCollectionOfComponents(member)
    
  3. Add your logic to :

    public void Map(ClassMappingBase classMap, Member member)
    { ... }
    
  4. Replace the default step with your new one :

    public class MyMappingConfiguration : DefaultAutomappingConfiguration
    {
        public override IEnumerable<IAutomappingStep> GetMappingSteps(AutoMapper mapper, IConventionFinder conventionFinder)
        {
            var steps = base.GetMappingSteps(mapper, conventionFinder);
            var finalSteps = steps.Where(c => c.GetType() != typeof(FluentNHibernate.Automapping.Steps.HasManyToManyStep)).ToList();
            var idx = finalSteps.IndexOf(steps.Where(c => c.GetType() == typeof(PropertyStep)).First());
            finalSteps.Insert(idx + 1, new MyCustomHasManyStep(this));
            return finalSteps; 
        }
    }
    

Note : You could also get the original source code of HasManyStep.cs and copy it to your project to introduce your custom logic.

like image 172
Kronos Avatar answered Sep 22 '22 16:09

Kronos