NHibernate объединяет две таблицы в одну сущность с помощью составного ключа - PullRequest
4 голосов
/ 12 июля 2011

У меня есть следующая структура данных:

+---------+
|Resume   |
+---------+
|Id (PK)  |
|IsActive |
|...      |
|..       |
|.        |
+---------+

+--------------------+
|Resume_Translation  |
+--------------------+
|ResumeId (PK, FK)   |
|Language (PK)       |
|Title               |
|Description         |
|...                 |
|..                  |
|.                   |
+--------------------+

Таким образом, у меня могут быть такие данные с двумя объединенными таблицами:

+----------------------------------------------------------+
|Id | IsActive | ResumeId | Language | Title | Description |
+----------------------------------------------------------+
|1  | true     | 1        | 'fr'     | 'One' | 'One desc'  |
|1  | true     | 1        | 'pl'     | 'Raz' | 'Raz Opis'  |
|2  | true     | 2        | 'fr'     | 'B'   | 'bla bla'   |
|3  | true     | 3        | 'fr'     | 'C'   | 'C bla bla' |
+----------------------------------------------------------+

С точки зрения моего домена, я забочусь только о Resume сущности. Я не хочу иметь Resume сущность с ее коллекцией Resume_Translations, потому что у меня будет только одна Resume сущность с текущим переводом.

public class Resume
{
    public virtual int Id{ get; protected internal set; }

    public virtual string Language { get; protected internal set; }

    public virtual string Title { get; protected internal set; }

    public virtual string Description { get; protected internal set; }

    public virtual bool IsActive { get; protected internal set; }
}

Мое текущее сопоставление с Fluent NHibernate выглядит следующим образом:

public class ResumeMap : ClassMap<Resume>
{

    public ResumeMap()
    {
        Table("Resume");
        Id(x => x.Id);
        Map(x => x.IsActive);
        // other properties
        Join("Resume_Translation", m =>
                        {
                            m.Fetch.Join();
                            m.Map(x => x.Language).Length(5);
                            m.Map(x => x.Title).Length(100);
                            m.Map(x => x.Description).Length(200);
                        });
    }
}

Я могу получить то, что хочу, из хранилища без проблем, просто передав WHERE предикат Id Resume и язык, который я хочу.

Однако у меня есть некоторые проблемы со вставкой и обновлением значений.

У меня такой вопрос: как определить отображение, которое NHibernate вставляет новую запись только в таблицу Resume_Translation вместо обновления записи для текущей сущности?

Так что я хочу достичь, если у меня есть в базе данных следующая запись:

|2  | true     | 2        | 'fr'     | 'B'   | 'bla bla'   |

Объединение подходит для отношений один к одному между таблицами, поэтому, если я включу это в свою сущность и поменяю язык и перевод, nhibernate выполняет обновление, и я могу это понять. Если я пытаюсь добавить новую сущность с тем же Id другим языком и переводом, nhibernate выдает ошибку, что ключ уже существует, и я тоже это понимаю.

Так что, конечно, я иду по неверному пути, но если кто-нибудь подскажет мне правильное решение о том, как я могу добиться нужного отображения, я был бы очень признателен.

Другой вопрос, как вы относитесь к сущностям и их переводам с точки зрения бизнеса?

Заранее спасибо за помощь.

Thomas

Ответы [ 3 ]

2 голосов
/ 12 июля 2011

Как насчет использования словаря, использования языка в качестве ключа?

public class ResumeTranslation
{
    public virtual string Title { get; protected internal set; }

    public virtual string Description { get; protected internal set; }
}

public class Resume
{
    public virtual int Id{ get; protected internal set; }

    // language is the key to the translation
    // you may even want to hide the dictionary from the public interface of
    // this class and only provide access to a "current" language.
    public virtual IDictionary<string, ResumeTranslation> Translations { get; private set; }

    public virtual bool IsActive { get; protected internal set; }
}

И сопоставьте его соответственно как map с составным элементом (извините, я не использую беглый, поэтому не спрашивайте меня, как это будет выглядеть). Это будет точно соответствовать вашей модели базы данных.

2 голосов
/ 12 июля 2011

Стефан на правильном пути. Я подправил его предложение создать двунаправленную ассоциацию, которая значительно облегчила бы обновление. Одним из преимуществ этого подхода является то, что вам нужно вручную назначать свойство Resume экземпляра ResumeTranslation при вставке, чтобы NHibernate правильно назначил ключ таблицы Resume строке ResumeTranslation. Итак, учитывая ассоциации, которые вы отображаете, это выглядит так, как в Fluent NH:

public class ResumeTranslation
{
    public virtual string Title { get; protected internal set; }

    public virtual string Description { get; protected internal set; }

             //Needed for bi-directional association:
    public virtual Resume Resume { get; set; }
}


public class ResumeTranslationMap : ClassMap<ResumeTranslation>
{

    public ResumeTranslationMap()
    {
        Table("ResumeTranslation");
        CompositeId()
            .KeyReference(kp => kp.Resume, "ResumeId")
            .KeyProperty(kp => kp.Language, "Language");

        Map(x => x.Title);
        Map(x => x.Description);
    }
}

public class ResumeMap : ClassMap<Resume>
{

    public ResumeMap()
    {
        Table("Resume");
        Id(x => x.Id);
        Map(x => x.IsActive);
        // other properties

        HasMany(c => c.Translations)
            .Inverse()
            .KeyColumn("id") //May not be required but here for reference
            .Cascade.All();
    }
}
2 голосов
/ 12 июля 2011

Похоже, отношения один ко многим со мной. Лично у меня была бы коллекция ResumeTranslation объектов в моем Resume объекте. Затем я бы сопоставил это со многими как стандартный.

Затем вы можете добавить другое свойство ActiveResumeTranslation к вашей Resume сущности, которая представляет вашу current translation.

...