My Domain auto mapping was working but now as I updated my NHibernate stack I'm getting mapping exception when Session Factory is building the Configuration:
"Can't figure out what the other side of the many-to-many property 'Users' should be."
The exception is thrown on a many to many map
The whole stack trace is this one:
at FluentNHibernate.Cfg.FluentConfiguration.BuildConfiguration() in
c:\hornget.horn\orm\fluentnhibernate\Working-2.1\src\FluentNHibernate\Cfg\FluentConfiguration.cs:line 119 at
WebApplication1.NHibernateManager.SessionFactoryManager.BuildConfiguration(AutoPersistenceModel
persistanceModel) in
C:\WebProgramming\Projects\WebApplication1\WebApplication1\NHibernateManager\SessionFactoryManager.cs:line 116 at
WebApplication1.NHibernateManager.SessionFactoryManager.GetSessionFactory() in
C:\WebProgramming\Projects\WebApplication1\WebApplication1\NHibernateManager\SessionFactoryManager.cs:line 71 at
WebApplication1.NHibernateManager.SessionManager.CloseSession() in
C:\WebProgramming\Projects\WebApplication1\WebApplication1\NHibernateManager\SessionManager.cs:line 47 at
WebApplication1.Global.Application_EndRequest(Object sender, EventArgs e) in
C:\WebProgramming\Projects\WebApplication1\WebApplication1\Global.asax.cs:line
36 at
System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
The Question is how to handle the many to many relationship properly using automapping.
Note: the mapping was working before i updated the NHibernate/FluentNHibernate stack...
Relevant definitions are pasted below:
The Domain classes (in Dll 1):
public class User : Entity
{
// ... removed properties
public virtual IList<Role> Roles { get; protected set; }//has many
// ... removed methods
}
public class Role : Entity
{
// ... removed properties
public virtual IList<User> Users { get; protected set; }//has many
// ... removed methods
}
Entity class (in DLL 2):
/// <summary>
/// Base Entity deffinition
/// </summary>
public abstract class Entity : IEquatable<Entity>
{
private int _Id = 0;
public virtual int Id { get { return _Id; } }
//... removed methods
}
Conventions:
public class PrimaryKeyConvention : IIdConvention
{
public void Apply(IIdentityInstance instance)
{
instance.Column(instance.EntityType.Name + "Id");
instance.GeneratedBy.HiLo("100");
instance.Access.ReadOnlyPropertyThroughPascalCaseField(PascalCasePrefix.Underscore);
}
}
public class ClassConvention : IClassConvention
{
public void Apply(IClassInstance instance)
{
instance.Table(Inflector.Pluralize(instance.EntityType.Name));
instance.LazyLoad();
instance.Cache.NonStrictReadWrite();
}
}
Many to Many Convention:
public class ManyToManyConvention : IHasManyToManyConvention
{
public void Apply(IManyToManyCollectionInstance instance)
{
if (instance.OtherSide == null)
{
instance.Table(
string.Format(
"{0}To{1}",
Inflector.Pluralize(instance.EntityType.Name),
Inflector.Pluralize(instance.ChildType.Name)));
instance.Cascade.AllDeleteOrphan();
}
else
{
instance.Inverse();
}
}
}
Model:
var persistanceModel = AutoMap.AssemblyOf<DataModelPaceholder>()
.AddEntityAssembly(typeof(Entity).Assembly)
.Conventions.AddFromAssemblyOf<ClassConvention>()
.UseOverridesFromAssemblyOf<DataModelPaceholder>()
.Setup(s =>
{
s.SubclassStrategy = t => SubclassStrategy.JoinedSubclass;
s.IsComponentType = type => type == typeof(MoneyComponent);
})
.IgnoreBase<Entity>()
.IgnoreBase<EntityAudit>()
//.IncludeBase<Product>()
.Where
(
type => typeof(Entity).IsAssignableFrom(type) && !type.IsAbstract
);