Getting error "Association references unmapped class" when using interfaces in model

549 views
Skip to first unread message

Bjarke Andersen-Sijtsma

unread,
Mar 12, 2010, 7:49:42 AM3/12/10
to Fluent NHibernate
I'm trying to use the automap functionality in fluent to generate a
DDL for the following model and program, but somehow I keep getting
the error "Association references unmapped class: IRole" when I call
the GenerateSchemaCreationScript method in NHibernate. When I replace
the type of the ILists with the implementation of the interfaces (User
and Role) everything works fine. What am I doing wrong here? How can I
make fluent use the implemented versions of IUser and IRole as defined
in Unity?

public interface IRole
{
string Title { get; set; }
IList<IUser> Users { get; set; }
}

public interface IUser
{
string Email { get; set; }
IList<IRole> Roles { get; set; }
}

public class Role : IRole
{
public virtual string Title { get; set; }
public virtual IList<IUser> Users { get; set; }
}
public class User : IUser
{
public virtual string Email { get; set; }
public virtual IList<IRole> Roles { get; set; }
}


I use the following program to generate the DDL using the
GenerateSchemaCreationScript in NHibernate:

class Program
{
static void Main(string[] args)
{
var ddl = new NHibernateSessionManager();
ddl.BuildConfiguration();
}
}

public class NHibernateSessionManager
{
private ISessionFactory _sessionFactory;
private static IUnityContainer _container;

private static void InitContainer()
{
_container = new UnityContainer();
_container.RegisterType(typeof(IUser), typeof(User));
_container.RegisterType(typeof(IRole), typeof(Role));
}

public ISessionFactory BuildConfiguration()
{
InitContainer();
return
Fluently.Configure().Database(MsSqlConfiguration.MsSql2008
.ConnectionString("ConnectionString"))
.Mappings(m => m.AutoMappings.Add(
AutoMap.AssemblyOf<IUser>()))
.ExposeConfiguration(BuildSchema)
.BuildSessionFactory();
}

private void BuildSchema(Configuration cfg)
{
var ddl = cfg.GenerateSchemaCreationScript(new
NHibernate.Dialect.MsSql2008Dialect());
System.IO.File.WriteAllLines("Filename", ddl);
}

}

OhadahO

unread,
Apr 1, 2010, 8:14:02 AM4/1/10
to Fluent NHibernate
Hi Bjarke,

I have the same problem...
did u manage to fix this? :-\

Thanks
Ohad


Asbjørn Ulsberg

unread,
May 12, 2010, 4:35:02 PM5/12/10
to fluent-n...@googlegroups.com
You need an .IgnoreBase<IUser> and .IgnoreBase<IRole> after
.AssemblyOf<IUser>() in BuildConfiguration().


-Asbjørn
--
You received this message because you are subscribed to the Google Groups "Fluent NHibernate" group.
To post to this group, send email to fluent-n...@googlegroups.com.
To unsubscribe from this group, send email to fluent-nhibern...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/fluent-nhibernate?hl=en.

Jason Duffett

unread,
May 13, 2010, 6:42:38 AM5/13/10
to Fluent NHibernate
I implemented the same thing and had the same problem at first.
Our domain model is based on interfaces instead of concrete classes
just like in the example.
I didn't use IgnoreBase<> but instead setup a ProxyConvention to map
interfaces to the appropriate concrete class and back.

I'm not sure if this is the best solution or not as i'm still testing
out how our automappings will work.
It currently just does looks for interfaces / classes based on the
convention of the interface being the same name as the concrete class
prefixed with "I". (I understand the objections to this naming
convention for interfaces).

public class EntityInterfaceProxyConvention : ProxyConvention
{
public EntityInterfaceProxyConvention()
: base(GetEntityInterfaceFromConcreteClass,
GetConcreteClassFromEntityInterface)
{
}

public static Type GetEntityInterfaceFromConcreteClass(Type
concrete)
{
// Check the class for interface with the same name,
prefixed with "I".
var iface = concrete
.GetInterfaces()
.FirstOrDefault(i => i.Name == "I" + concrete.Name);

return iface;
}

public static Type GetConcreteClassFromEntityInterface(Type
iface)
{
// Only support interfaces
if (!iface.IsInterface)
return null;
// Only support interfaces following the IEntityType
naming convention
if (iface.Name[0] != 'I')
return null;

// Search all loaded assemblies
var concrete = AppDomain.CurrentDomain.GetAssemblies()
// Which start with our prefix "MyNamespace"
.Where(a => a.FullName.StartsWith("MyNamespace"))
// Select all types in the assembly
.Select(a => a.GetExportedTypes()
// Which are classes and implement iface
.Where(t => t.IsClass && t.Implements(iface))
.FirstOrDefault())
// Null values returned for assemblies that have no
matching class
.FirstOrDefault(t => t != null);

return concrete;
}
}


Jason
Reply all
Reply to author
Forward
0 new messages