views:

812

answers:

4

Please consider the following simple use case:

public class Foo 
{ 
    public virtual int Id 
    { 
        get; 
        protected set; 
    } 
    public virtual IBar Bar 
    { 
        get; 
        set; 
    } 
} 

public interface IBar 
{ 
    string Text 
    { 
        get; 
        set; 
    } 
} 

public class Bar : IBar 
{ 
    public virtual string Text 
    { 
        get; 
        set; 
    } 
} 

And the fluent-nhibernate map class:

public class FooMap : ClassMap<Foo> 
{ 
    public FooMap() 
    { 
        Id(x => x.Id); 
        Component(x => x.Bar, m => 
        { 
            m.Map(x => x.Text); 
        }); 
    } 
} 

While running any query with configuration, I get the following exception:

NHibernate.InstantiationException: "Cannot instantiate abstract class or interface: NHMappingTest.IBar"

It seems that NHibernate tries to instantiate an IBar object instead of the Bar concrete class. How to let Fluent-NHibernate know which concrete class to instantiate when the property returns an interface or an abstract base class?

EDIT: Explicitly specify the type of component by writing Component<Bar> (as suggested by Sly) has no effect and causes the same exception to occur.

EDIT2: Thanks to vedklyv and Paul Batum: such a mapping should be soon is now possible.

A: 

Maybe this?

public FooMap()
 {
  Id(x => x.Id);
  Component<Bar>(x => x.Bar, m =>
  {
   m.Map(x => x.Text);
  });
 }
Sly
Unfortunately, it does not work (same exception). It seems that Fluent-NHibernate does not use the generic type to infer the type of the component. Instead, it seems to use reflection to get that piece of info directly from the lambda expression parameter.
Yann Trevin
A: 

Here's a similar topic using the union-subclass approach, although the example does not use the fluent interface for the map:

Click for article...

Jared
+2  A: 

I haven't tried this myself but i saw an example in the fluent nh source where the lambda is cast to the concrete class:

public class FooMap : ClassMap<Foo> 
{ 
    public FooMap() 
    { 
        Id(x => x.Id); 
        Component(x => (Bar) x.Bar, m => 
        { 
            m.Map(x => x.Text); 
        }); 
    } 
}

EDIT: Obviously that's exactly the same result as Sly's suggestion so that did no good. I tested it against the trunk version of fluent nh and it didn't work. It does work though if you use a many-to-one mapping:

  public class FooMap : ClassMap<Foo>
  {
    public FooMap()
    {
      Id(x => x.Id);
      References<Bar>(x => x.Bar).Cascade.All();
    }
  }

  public class BarMap : ClassMap<Bar>
  {
    public BarMap()
    {
      Id(x => x.Id);
      Map(x => x.Text);
    }
  }

UPDATE

This was actually an easy fix. I have submitted a patch (link text) that makes Sly's solution to work.

johannesg
(+1) Thank you for having submitted a patch to the development team of FNH.
Yann Trevin
A: 

Have not used the fluent NHibernate yet but seems to me what you are trying to do is map to an IUserType which you haven't told hibernate how to deal with. here is a useful example for defined usertypes in fluent.

http://blog.jagregory.com/2009/01/11/fluent-nhibernate-auto-mapping-type-conventions/

AndrewB