FluentNHibernate AutoPersistenceModel with Interfa

2019-07-28 07:12发布

问题:

I am trying out the FluentNHibernate AutoPersistenceModel for the first time. It was very simple to get a basic example working but I am having a problem making it fit with how I work. I normally work to interfaces so that my entities all implement an interface and reference all related entities by their interface, not their concrete type. Given the following classes:

public Interface IFoo { }

public Interface IBar { IFoo Foo { get; set; } }

public Class Foo : IFoo { }

public Class Bar : IBar
{
     public IFoo Foo { get; set; }
}

I would have the following mapping:

public class BarMapping : ClassMap<Bar>
{
    public AnswerMapping()
    {
        References<Foo>( x => x.Foo ).Column( "FooId" ).Cascade.None();
    }
}

How would I achieve the same with the AutoPersistenceModel? I have had a brief look at Conventions and the ReferenceConvention builder but without any documentation or examples I have been floundering.

EDIT

I have now turned this along with my other SO post on collection mapping to interfaces into a blog post: http://bronumski.blogspot.com/2011/01/making-fluent-nhibernate-automapper.html

回答1:

After a little digging around I have come up with a solution. There is an IReferenceConvention interface which I have seen used in other examples but don't cover this scenario. By implementing the interface and doing a custom convention I have been able to achieve the same thing with the AutoPersistenceModel that I was with ClassMap.

public class ReferenceConvention : IReferenceConvention
{
    public void Apply(IManyToOneInstance instance)
    {
        Type instanceType = instance.Class.GetUnderlyingSystemType();
        if (instanceType == typeof(IFoo))
        {
            instance.CustomClass<Foo>();
        }

        instance.Cascade.All();
    }
}

A more generic approach might be:

public class ReferenceConvention : IReferenceConvention
{
    public void Apply(IManyToOneInstance instance)
    {
        Type instanceType = instance.Class.GetUnderlyingSystemType();

        if (instanceType.IsInterface)
        {
            // Assuming that the type starts with an I get the name of the concrete class
            string className = instanceType.Name.Substring( 1 );

            instance.CustomClass(instanceType.Assembly.GetType(
                instanceType.FullName.Replace( instanceType.Name, className )));
        }

        instance.Cascade.All();
    }
}

There is also a ReferenceConventionBuilder which I have not looked at yet but this could be a cleaner solution.