4
votes

My schema

I have a class diagram looking like the picture above. I use NHibernate to do CRUD commands on the objects. When I write to the permission table (adds a role to the user’s role collection and vice versa), NHibernate starts acting strange. I have a Method called UpdateRoles() that makes sure that all Roles are up to date. This method fails as NHibernate sometimes generates proxy objects, hence UpdateRoles() now think the Role does not exist and makes a new object (causing my hierarchy to be duplicated). I found a pattern for when NHibernate loads objects as proxies:

enter image description here

Case 1 works, case 2 doesn’t. What happens is that in case 1 the user is added to the user collection of each Role in each 3 levels of the hierarchy. This is working as intended.

In case 2, the user is only added to the last level in the hierarchy. Now the parent role (uCommerce) is loaded as a proxy object. My RoleMap looks like this:

References(x => x.ParentRole).Nullable().Column("ParentRoleId");                    
HasManyToMany(x => x.Users).AsSet().Table("uCommerce_Permission");          
HasMany(x => x.Roles).Inverse().KeyColumn("ParentRoleId").Cascade.AllDeleteOrphan();

My UserMap looks like this:

HasManyToMany(x => x.Roles).AsSet().Table("uCommerce_Permission");    

How can I prevent NHibernate from doing this? I use Fluennt NHibernate. Specifying Not().LazyLoad() doesn't prevent the problem. Also i read that specifying such is a bad case of programming.

1
Code for the UpdateRoles method might help - kͩeͣmͮpͥ ͩ
The UpdateRoles method is pretty huge. But it searches the DB for an object based on the parentrole and the type: typeof (CreateProductRole) == x.GetType(). This causes it to think no object exists as the type is Not of CreateProductRole but of a proxy type. Hope that clarifies it a little. - Morten Skjoldager
there's usually something wrong with your design when your start asking for the type of something. You could always query CreateProductRole that has the current Role as a child. - kͩeͣmͮpͥ ͩ
The problem is that every role has 0..* childs and the only way to know the difference is with a discriminatorvalue (which basicly is the same as GetType(). That is why i use GetType. - Morten Skjoldager

1 Answers

0
votes

1)

var proxy = parent as INHibernateProxy;
if (proxy != null)
{
    // var t = x.GetType(); becomes
    var t = proxy.HibernateLazyInitializer.GetImplementation().GetType();
}

or 2)

References(x => x.ParentRole).Nullable().Column("ParentRoleId").Not.LazyLoad();

or 3)

ReferencesAny(x => x.ParentRole)
    .Nullable()
    .EntityIdentifierColumn("ParentRoleId")
    .EntityTypeColumn("parentdiscriminator");

typeof(CreateProductRole).IsAssignableFrom(role.Parent.GetType()).

1) and 2) are basicly the same, the parent is not lazyloaded

3) means that each role knows the type of its parent so that when a proxy is created, it is a proxy for the actual role type (CreateProductRoleProxy) and not RoleProxy