开发者

NHibernate HasMany relation. Collection is null until session reopen

开发者 https://www.devze.com 2023-02-26 18:44 出处:网络
I\'ve got a problem with NHibernate and, as I suppose, with lazy load. I\'ve got two entity classes, that are related to each other:

I've got a problem with NHibernate and, as I suppose, with lazy load.

I've got two entity classes, that are related to each other:

public class User
{
    // lots of properties
    public virtual Role Role { get; set; }
}

public class Role
{
    // properties
    public virtual IList<User> UsersInRole { get;set; }
    public Role()
    {
        this.UsersInRole = new List<User>();
    }
}

Relation is One-To-Many (One role - Many users). Classes are mapped with Fluent as following:

public class UserMapping : ClassMap<Models.Accounts.User>
{
    public UserMapping() 
    {
        this.Table("Users");
        this.Id(u => u.ID).GeneratedBy.Native();
        //properties mapping            
        this.References<Models.Accounts.Role>(u => u.Role);
    }
}

public class RoleMapping : ClassMap<Models.Accounts.Role>
{
    public RoleMapping()
    {
        this.Table("Roles");
        this.Id(r => r.ID).GeneratedBy.Native();
        // properties mapping 
        this.HasMany<User>(r => r.Users).AsBag().Inverse().KeyColumn("Role_id");
    }
}

When I'm creating a Role, and assign some User to it - Role::Users property is null until session is close开发者_运维知识库d and another one is opened. So, consider following code:

object Foo()
{
        var session = FluentManager.OpenNewSession();
        var t1 = session.BeginTransaction();
        Role role = new Role("admin");
        session.SaveOrUpdate(role);
        t1.Commit();

        var t2 = session.BeginTransaction();
        session.SaveOrUpdate(new User() { Login = "log1", Role = role });
        t2.Commit();            

        Role oldRole = session.Get<Role>((uint)1);
        return oldRole.Users; // null here
}

On the other hand, following code works fine:

object Foo()
{
        var session = FluentManager.OpenNewSession();
        var t1 = session.BeginTransaction();
        Role role = new Role("admin");
        session.SaveOrUpdate(role);
        t1.Commit();

        var t2 = session.BeginTransaction();
        session.SaveOrUpdate(new User() { Login = "log1", Role = role });
        t2.Commit();
        session.Close();

        var session2 = FluentManager.OpenNewSession();
        Role oldRole = session2.Get<Role>((uint)1);
        return oldRole.Users; // Actual list of users
}

Though, I'd like to work with collection of users in a given role w/out session close. What I did wrong? Many thanks in advance.

PS: I'm using Fluent NHibernate 1.2 with SQLite database, if that matters.


The reason why role.Users is null in the first example is because you don't manually take care of this relationship. You need to maintain the bidirectional relationship yourself. In your first example it is not getting your Role object from the database. It's getting it from Session. In your 2nd example you close your session and open a new one. This forces it to read the information from the database and your relationships will be intact at this point. Here is what I might do to correct this:

public class User
{
    // lots of properties
    public virtual Role Role { get; set; }
}

public class Role
{
    // properties
    public virtual IList<User> UsersInRole { get;set; }

    public Role()
    {
        this.UsersInRole = new List<User>();
    }

    public void AddUser(User user)
    {
        if(UsersInRole.Contains(user))
            return;

        user.Role = this;
        UsersInRole.Add(user);
    }
}

Your example would now look something like this:

object Foo()
{
        var session = FluentManager.OpenNewSession();
        var t1 = session.BeginTransaction();
        Role role = new Role("admin");
        session.SaveOrUpdate(role);
        t1.Commit();

        var t2 = session.BeginTransaction();
        User newUser = new User();
        newUser.Login = "log1";

        //This takes care of our relationships
        role.AddUser(newUser);

        session.SaveOrUpdate(newUser);
        t2.Commit();            

        Role oldRole = session.Get<Role>((uint)1);
        return oldRole.Users; // This should be fine here since we used AddUser
}

You can also take a look at the following for more detail:
Getting ManyToMany relationship to load


Some shots in the dark:

Have you tried accessing role.Users instead of oldRole.Users?

Have you tried removing the constructor of Role?

Have you tried getting the role using a detached criteria or QueryOver rather than Get? Maybe you're getting the wrong role.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号