Вопрос по many-to-many, one-to-many, domain-model, fluent-nhibernate, nhibernate – Связи NHibernate «многие ко многим», делающие оба конца родительскими, с помощью сущности отношения в модели предметной области

1

Объекты: Команда <-> TeamEmployee <-> Работник

Требования:

Команда и Сотрудник могут существовать без своего коллеги.В отношении Team-TeamEmployee команда несет ответственность (родитель) [используя позже TeamRepository].В отношении Employee-TeamEmployee Сотрудник несет ответственность (родитель) [используя позже EmployeeRepository].Дубликаты не допускаются.Удаление команды удаляет всех сотрудников в команде, если сотрудник не входит в другую команду.При удалении сотрудника удаляется только команда, если в команде больше нет сотрудников.

Отображение:

public class TeamMap : ClassMap
{
    public TeamMap()
    {
        // identity mapping
        Id(p => p.Id)
            .Column("TeamID")
            .GeneratedBy.Identity();

        // column mapping
        Map(p => p.Name);

        // associations
        HasMany(p => p.TeamEmployees)
            .KeyColumn("TeamID")
            .Inverse()
            .Cascade.SaveUpdate()
            .AsSet()
            .LazyLoad();
    }
}

public class EmployeeMap : ClassMap
{
    public EmployeeMap()
    {
        // identifier mapping
        Id(p => p.Id)
            .Column("EmployeeID")
            .GeneratedBy.Identity();

        // column mapping
        Map(p => p.EMail);
        Map(p => p.LastName);
        Map(p => p.FirstName);

        // associations
        HasMany(p => p.TeamEmployees)
            .Inverse()
            .Cascade.SaveUpdate()
            .KeyColumn("EmployeeID")
            .AsSet()
            .LazyLoad();

        HasMany(p => p.LoanedItems)
            .Cascade.SaveUpdate()
            .LazyLoad()
            .KeyColumn("EmployeeID");
    }
}

public class TeamEmployeeMap : ClassMap
{
    public TeamEmployeeMap()
    {
        Id(p => p.Id);

        References(p => p.Employee)
            .Column("EmployeeID")
            .LazyLoad();

        References(p => p.Team)
            .Column("TeamID")
            .LazyLoad();
    }
}

Создание сотрудников и команд:

    var employee1 = new Employee { EMail = "Mail", FirstName = "Firstname", LastName = "Lastname" };
    var team1 = new Team { Name = "Team1" };
    var team2 = new Team { Name = "Team2" };

    employee1.AddTeam(team1);
    employee1.AddTeam(team2);


    var employee2 = new Employee { EMail = "Mail2", FirstName = "Firstname2", LastName = "Lastname2" };
    var team3 = new Team { Name = "Team3" };

    employee2.AddTeam(team3);
    employee2.AddTeam(team1);

    team1.AddEmployee(employee1);
    team1.AddEmployee(employee2);
    team2.AddEmployee(employee1);
    team3.AddEmployee(employee2);

    session.SaveOrUpdate(team1);
    session.SaveOrUpdate(team2);
    session.SaveOrUpdate(team3);

    session.SaveOrUpdate(employee1);
    session.SaveOrUpdate(employee2);

После этого я фиксирую изменения с помощью транзакции.Commit (). Первая странная вещь заключается в том, что я должен спасти Команды и Сотрудников, а не одну из них (почему ?!). Если я сохраню только все команды или (Xor) всех сотрудников, тогда я получуTransientObjectException:»

объект ссылается на несохраненный временный экземпляр - сохраните временный экземпляр перед сбросом. Тип: Core.Domain.Model.Employee, Entity: Core.Domain.Model.Employee "

Когда я сохраняю все созданные Команды и Сотрудники, все сохраняется нормально, НО таблица отношений TeamEmployee имеетдубликаты ассоциаций.

ID EID TID
1  1   1
2  2   1
3  1   2
4  2   3
5  1   1
6  1   2
7  2   3
8  2   1

Таким образом, вместо 4 отношений есть 8 отношений. 4 отношения для левой стороны и 4 отношения для правой стороны. : [

Что я не прав?

Дополнительные вопросы: Когда я удаляю команду или сотрудника, нужно ли мне удалять команду или сотрудника из списка TeamEmployee в объектной модели, или NHibernate выполняет работу за меня (используя session.delete (..))?

Ваш Ответ

4   ответа
1

Проверять, выписыватьсяэтот уроки, в частности, как отображение междуProduct а такжеStore настроен.

Отображение связи «многие ко многим» с NH не позволяет обоим концам ассоциации быть родителями, поэтому я использую третий объект отношения. В этом отображении существует только один родитель и один ребенок. Rookian
Брилл, спасибо! dav_i
Привет, ссылка не работает. dav_i
@dav_i: Спасибо, что указали на это. У меня нетя очень долго работал с Fluent Nhibernate, но я надеюсьих новое руководство по началу работы содержит примерно то же самое, что и старый. Tomas Aschan
0

NHibernate не позволяет многим-многим общаться с родителями на обоих концах.

Вы уверены, что NH обычно не позволяет многим-многим общаться с родителями на обоих концах? Я думаю, что это не работает с ключевым словом NH многие-многие, но с ассоциациями один-ко-многим, нене так ли? Rookian
2

Вы говорите о бизнес-логике. Это'Не цель NHibernate для реализации бизнес-логики.

Что делает ваш код:

Вы сопоставили две разные коллекцииTeamEmployeeс, один вTeam, один вEmployee, В своем коде вы добавляете элементы в обе коллекции, создавая новые экземплярыTeamEmployee каждый раз. Так почему вы ожидаете, что NHibernate не должен хранить все эти отдельные экземпляры?

Что вы можете сделать, чтобы это исправить:

Ты сделалTeamEmployee сущность (в отличие от типа значения). Чтобы создать экземпляр только один раз, вам нужно будет создать его экземпляр только один раз в памяти и повторно использовать в обеих коллекциях. Делайте это только тогда, когда вам действительно нужен этот класс в вашей доменной модели. (Например, потому что он содержит дополнительную информацию об отношениях и фактически сам по себе.)

Если вы неКласс не нужен, гораздо проще отобразить его как отношение многие ко многим (как уже было предложеноКрис Конвей). Поскольку в памяти есть две коллекции, которые, как ожидается, будут содержать одни и те же данные, вы говорите NHibernate игнорировать одну из них при хранении и использовании.Inverse

Родитель на обоих концах проблемы

Здесь нетродитель на обоих концах, Я думаю это'Понятно, что ни команда, ни сотрудник не являются родителями другого, они независимы. Вы, вероятно, имеете в виду, что они оба родители промежуточногоTeamEmployee, Они могут't быть родителем (и, следовательно, владельцем) одного и того же экземпляра. Либо один из них является родительским, либо это другой независимый экземпляр, что значительно усложняет управление им (именно так вы реализовали его сейчас). Если вы отобразите его как отношение «многие ко многим», оно будет управляться NHibernate.

Для выполнения вашей бизнес-логики:

хранение новых команд и новых сотрудниковуправление отношениями и их синхронизацияудаление команд и сотрудников, когда они больше не используются. (Там явно нетпостоянная сборка мусора реализация в NHibernate по нескольким причинам.)
... и как мне удалить команду с настройкой из Криса Конвея? Rookian
почему у команды нет опции каскадирования? Rookian
Я бы неЗдесь все каскадно, но это дело вкуса. ИМХО, когда есть две независимые сущности, ссылающиеся друг на друга, должна быть бизнес-логика для их создания, а не каскадирование. Даже если вам нужно заботиться об этом в коде, этояснее. --- Когда вы удаляете команду, вам нужно пройтись по сотрудникам и удалить их всех. Когда вы удаляете сотрудника, вы можете использовать запрос, который возвращает все упомянутые команды, у которых нет других сотрудников, и удаляет их тоже. Вы можете использовать HQL для непосредственного удаления объектов без их загрузки. Stefan Steinegger
1

Похоже, вам нужно HasManyToMany вместо двух карт HasMany. Кроме того, в TeamEmployeeMap нет необходимости, если в этой таблице нет другого свойства, которое необходимо сопоставить. Другое дело, что только одна сторона должна иметь Inverse (), и так как вы 'добавление команд к сотрудникам Думаю, вам нужно сделать TeamMap обратным. Наличие инверсии только на одной стороне избавит от повторяющихся записей в базе данных.

Может быть, что-то вроде этого:

public class TeamMap : ClassMap
{
    public TeamMap()
    {
        // identity mapping
        Id(p => p.Id)
           .Column("TeamID")
           .GeneratedBy.Identity();

        // column mapping
        Map(p => p.Name);

        // associations
        HasManyToMany(x => x.TeamEmployees)
            .Table("TeamEmployees")
            .ParentKeyColumn("TeamID")
            .ChildKeyColumn("EmployeeID")
            .LazyLoad()
            .Inverse()
            .AsSet();
    }
}

public class EmployeeMap : ClassMap
{
    public EmployeeMap()
    {
        // identifier mapping
        Id(p => p.Id)
            .Column("EmployeeID")
            .GeneratedBy.Identity();

        // column mapping
        Map(p => p.EMail);
        Map(p => p.LastName);
        Map(p => p.FirstName);

        // associations
        HasManyToMany(x => x.TeamEmployees)
            .Table("TeamEmployees")
            .ParentKeyColumn("EmployeeID")
            .ChildKeyColumn("TeamID")
            .Cascade.SaveUpdate()
            .LazyLoad()
            .AsSet();

        HasMany(p => p.LoanedItems)
            .Cascade.SaveUpdate()
            .LazyLoad()
            .KeyColumn("EmployeeID");
    }
}

Используя это, удаление удалит TeamEmployee из базы данных для вас.

Отображение связи «многие ко многим» с NH не позволяет обоим концам ассоциации быть родителями, поэтому я использую третий объект отношения. Rookian

Похожие вопросы