NHibernate HasMany отношения.Коллекция является нулевой, пока сессия не возобновится - PullRequest
1 голос
/ 19 апреля 2011

У меня проблема с NHibernate и, как я полагаю, с ленивой загрузкой.

У меня есть два класса сущностей, которые связаны друг с другом:

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>();
    }
}

Отношение один-ко-многим (одна роль - много пользователей).Классы отображаются с помощью Fluent следующим образом:

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");
    }
}

Когда я создаю роль и назначаю ей одного пользователя - свойство Role :: Users будет нулевым, пока сессия не будет закрыта, а другой откроется.Итак, рассмотрим следующий код:

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
}

С другой стороны, следующий код работает нормально:

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
}

Хотя я бы хотел работать с коллекцией пользователей в данной ролибез закрытия сессии.Что я сделал не так?Заранее большое спасибо.

PS: я использую Fluent NHibernate 1.2 с базой данных SQLite, если это имеет значение.

Ответы [ 2 ]

2 голосов
/ 22 апреля 2011

Причина, по которой role.Users является нулевым в первом примере, заключается в том, что вы не заботитесь об этих отношениях вручную.Вы должны поддерживать двусторонние отношения самостоятельно.В вашем первом примере это не получение объекта Role из базы данных.Это получает это от Сессии.Во втором примере вы закрываете сеанс и открываете новый.Это вынуждает его читать информацию из базы данных, и ваши отношения будут целы на этом этапе.Вот что я могу сделать, чтобы исправить это:

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);
    }
}

Ваш пример теперь будет выглядеть примерно так:

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
}

Вы также можете взглянуть на следующее для более подробной информации:
Получение отношения ManyToMany для загрузки

0 голосов
/ 20 апреля 2011

Несколько снимков в темноте:

Вы пытались получить доступ к role.Users вместо oldRole.Users?

Вы пытались удалить конструктор Role?

Вы пытались получить роль, используя независимые критерии или QueryOver вместо Get? Может быть, вы получаете не ту роль.

...