在NHibernate中实现具有可翻译属性的实体的最佳方法

时间:2011-07-21 21:08:39

标签: nhibernate nhibernate-mapping

考虑以下类(为了集中于核心问题而简化):

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

如何映射Question类,以便使用当前线程的文化填充Text和Hint属性。如果线程的文化被更改,我希望Text和Hint属性自动返回适当的值,而不需要重新加载Question实体。

请注意,我只是概述了业务方面的相关类和属性。我对完成所需功能所需的任何新类或属性完全开放。

2 个答案:

答案 0 :(得分:2)

替代Firo的答案(是的,我复制了它并对其进行了调整并对此感到不满)。

它使用字典并将翻译映射为复合元素(因此它根本不需要id)

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 :(得分:1)

编辑以反映更改后的答案:

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>,但通常情况下应该这样做