Лучший способ реализовать Entity с переводимыми свойствами в NHibernate - PullRequest
2 голосов
/ 22 июля 2011

Рассмотрим следующий класс (упрощенный для того, чтобы сосредоточиться на основной задаче):

public class Question
{
    public virtual string QuestionId { get; set; }

    public virtual string Text { get; set; }

    public virtual string Hint { get; set; }
}

и таблицы:

Question
- QuestionId ((primary key, identity column and key)
- Code

QuestionTranslation
- QuestionTranslationId (primary key, identity column; not really relevant to the association)
- QuestionId (composite key element 1)
- CultureName (composite key element 2) (sample value: en-US, en-CA, es-ES)
- Text
- Hint

Как я могу отобразить класс Вопроса так, чтобы тексти свойства подсказки заполняются с использованием культуры текущего потока.Если культура потока изменилась, я бы хотел, чтобы свойства Text и Hint автоматически возвращали соответствующее значение без необходимости перезагружать сущность Question.

Обратите внимание, что я только выделяю соответствующий класс и свойства изделовая сторона.Я полностью открыт для любого нового класса или свойства, необходимого для достижения желаемой функциональности.

Ответы [ 2 ]

2 голосов
/ 10 августа 2011

Альтернатива ответу Firo (да, я скопировал его, адаптировал и чувствую себя плохо по этому поводу).

Он использует словарь и отображает переводы как составной элемент (поэтому ему не нужен идентификаторна все)

public class Question
{
    public virtual string QuestionId { get; set; }

    public virtual string Text
    {
        get
        {
            var translation = Translations[CultureInfo.CurrentCulture.Name];
            if (translation != null) return translation.Text
            return null;
        }
        set
        {
            GetTranslation(CultureInfo.CurrentCulture.Name).Text = value;
        }
    }

    public virtual string Hint
    {
        get
        {
            var translation = Translations[CultureInfo.CurrentCulture.Name];
            if (translation != null) return translation.Hint
            return null;
        }
        set
        {
            GetTranslation(CultureInfo.CurrentCulture.Name).Hint = value;
        }
    }


    private QuestionTranslation GetTranslation(CultureInfo.CurrentCulture.Name)
    {
        QuestionTranslation translation;
        if (!Translations.TryGetValue(CultureInfo.CurrentCulture.Name, out translation))
        {
           translation = new QuestionTranslation()
           Translations[CultureInfo.CurrentCulture.Name] = translation;
        }
        return translation;
    }

    protected virtual IDictionary<string, QuestionTranslation> Translations { get; private set; }
}

class QuestionTranslation
{
    // no id, culture name
    public virtual string Text { get; set; }
    public virtual string Hint { get; set; }
}

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

<class name="Question">
  <id name="QuestionId" column="QuestionId"/>

  <map name="Translations" table="QuestionTranslation" lazy="true">
    <key column="QuestionId"/>
    <index column="CultureName"/>
    <composite-element class="QuestionTranslation">
      <property name="Text"/>
      <property name="Hint"/>
    </composite-element>
  </bag>
</class>
1 голос
/ 25 июля 2011

Отредактировано, чтобы отразить измененный ответ:

public class Question
{
    public virtual string QuestionId { get; set; }

    public virtual string Text
    {
        get
        {
            var currentculture = CultureInfo.CurrentCulture.Name;
            return Translations
                .Where(trans => trans.CultureName == currentculture)
                .Select(trans => trans.Text)
                .FirstOrDefault();
        }
        set
        {
            var currentculture = CultureInfo.CurrentCulture.Name;
            var translation = Translations
                .Where(trans => trans.CultureName == currentculture)
                .FirstOrDefault();
            if (translation == null)
            {
                translation = new QuestionTranslation();
                Translations.Add(translation);
            }
            translation.Text = value;
        }
    }
    public virtual string Hint
    {
        get
        {
            var currentculture = CultureInfo.CurrentCulture.Name;
            return Translations
                .Where(trans => trans.CultureName == currentculture)
                .Select(trans => trans.Hint)
                .FirstOrDefault();
        }
        set
        {
            var currentculture = CultureInfo.CurrentCulture.Name;
            var translation = Translations
                .Where(trans => trans.CultureName == currentculture)
                .FirstOrDefault();
            if (translation == null)
            {
                translation = new QuestionTranslation();
                Translations.Add(translation);
            }
            translation.Hint = value;
        }
    }

    protected virtual ICollection<QuestionTranslation> Translations { get; set; }
}

class QuestionTranslation
{
    public virtual int Id { get; protected set; }
    public virtual string CultureName { get; set; }
    public virtual string Text { get; set; }
    public virtual string Hint { get; set; }
}

<class name="Question" xmlns="urn:nhibernate-mapping-2.2">
  <id name="QuestionId" column="QuestionId"/>

  <bag name="Translations" table="QuestionTranslation" lazy="true">
    <key>
      <column name="QuestionId"/>
    </key>
    <one-to-many class="QuestionTranslation"/>
  </bag>
</class>

<class name="QuestionTranslation" table="QuestionTranslation" xmlns="urn:nhibernate-mapping-2.2">
  <id name="QuestionTranslationId"/>
  <many-to-one name="ParentQuestion" column="QuestionId"/>
</class>

если у вас много переводов, измените ICollection<QuestionTranslation> Translations { get; set; } на IDictionary<string, QuestionTranslation> Translations { get; set; } и отобразите как <map>, но, как правило, вышеописанное должно это сделать

...