I have the following entities:
User
Role
and then a join table:
UsersRoles (UserId, RoleId)
and then a RolePermissions table:
RolePermissions(Id, RoleId, ....)
So on the User entity I want to be able to do:
user.Roles
user.RolePermissions
My UserMap looks like:
public class UserMap : ClassMap<User>
{
public UserMap()
{
HasManyToMany(x => x.Roles)
.Table("RolesUsers")
.Access.CamelCaseField(Prefix.Underscore)
.ParentKeyColumn("UserId")
.ChildKeyColumn("RoleId")
.Cascade.All()
.Inverse();
}
}
Now when I create a new user like:
var user = new User { ... };
user.AddRole(new Role { .... } );
UserRepository.Create(user);
It saves the user, and saves the role, but doesn't insert into the RolesUsers table?
Also how do I add a property to get all the RolePermissions for a User?
Update
My rolemap has:
HasManyToMany(x => x.Users)
.Table("RolesUsers")
.Access.CamelCaseField(Prefix.Underscore)
.ParentKeyColumn("RoleId")
.ChildKeyColumn("UserId")
.Cascade.All();
My unit test actually passes, but I think it is because I don't know how to purge the 1st level cache and it isn't even querying the database with the call for testUser
:
[Test]
public void ShouldAddARoleToAUser()
{
int userId = -1;
using (var tx = UserRepository.SessionFactory.OpenSession().BeginTransaction())
{
var user = FactoryGirl.GetUser();
user.AddRole(FactoryGirl.GetRole());
UserRepository.Create(user);
tx.Commit();
UserRepository.SessionFactory.OpenSession().Flush();
userId = user.Id;
}
var testUser = UserRepository.Get(userId);
Assert.IsNotNull(testUser);
Assert.IsNotNull(testUser.Roles);
Assert.IsTrue(testUser.Roles.Count == 1);
Assert.IsTrue(testUser.Roles[0].Id > 0);
}
Update II
My user.cs looks like:
private IList<Role> _roles = new List<Role>();
public virtual IList<Role> Roles
{
get { return _roles; }
}
public virtual void AddRole(Role role)
{
if(!_roles.Contains(role))
{
_roles.Add(role);
}
}
Role.cs:
private IList<User> _users = new List<User>();
public virtual IList<User> Users
{
get { return _users; }
}
Update III
The strange this is my test passes, but looking at profiler I can see that it doesn't even hit sql server so even though I am calling Flush, and then doing a Get(userId) it is loading the entity from memory. Also, looking at the other end of the relation (Role), the Role.Users is {} so is that the issue?
If you are using private backing fields for your collections I think you have to map them like this:
public class UserMap : ClassMap<User>
{
public UserMap()
{
HasManyToMany(x => x.Roles)
.Table("RolesUsers")
.Access.AsCamelCaseField(Prefix.Underscore)
.ParentKeyColumn("UserId")
.ChildKeyColumn("RoleId")
.Cascade.All()
.Inverse();
}
}
Key difference above is .Access.AsCamelCaseField(Prefix.Underscore)
In addition to this I think you need to simplify your test to something like the following:
User newUser = new User();
Role newRole = new Role();
newUser.AddRole(newRole);
newRole.AddUser(newUser);
using (NHibernate.ISession session = iSessionFactory.OpenSession())
{
using (NHibernate.ITransaction tran = session.BeginTransaction())
{
session.Save(newUser);
tran.Commit();
}
}
The above may not be exact but I think you get the idea of what I'm talking about.