使用NHibernate实现多语言域对象的最佳方法是什么?

时间:2010-05-19 11:53:27

标签: asp.net sql-server nhibernate hibernate multilingual

设计可以具有多语言字段的Domain对象的最佳方法是什么。一个示例可以是Product类,其中Description是多语言的。

我找到了很少的链接,但无法确定哪一个是最好的方式。

  1. http://fabiomaulo.blogspot.com/2009/06/localized-property-with-nhibernate.html
    (这会将所有本地化语言数据存储在一个字段中。如果我们从Sql查询,则可能会出现问题)

  2. http://ayende.com/Blog/archive/2006/12/26/LocalizingNHibernateContextualParameters.aspx
    (这个开头有一个警告,它是一个黑客,不再支持)

  3. http://www.webdevbros.net/2009/06/24/create-a-multi-languaged-domain-model-with-nhibernate-and-c/
    (这没有描述如何在数据库中构建多语言数据。)

  4. 任何有使用NHibernate和多语言数据经验的人。还有更好的方法吗?

4 个答案:

答案 0 :(得分:2)

第三种选择看起来很棒。给出了hibernate映射,但没有给出数据库模式 - 如果这是你缺少的,那么我将在这里草拟它:

dictionary
----------
ID: int - identity
name: nvarchar(255)

phrase
------
dictionary_id:int  (fkey dictionary.ID)
culture_id:int     (LCID)
phrase:nvarchar(255)  - this is the default size - seems too small

根据this blog entry,255是String值的默认字符串长度。要克服短语文本中的短字符串长度,您可以将<element>标记更改为

<element column="phrase" type="String" length="4001"></element>

要在您的域模型中使用此功能,请向您想要可翻译文本的实体添加PhraseDictionary属性。例如。 title属性或decription属性。

我认为这篇文章描述了一个很好的方法,而且是我要去的方法 对于。

编辑:在回复评论时,如果您知道绝对最大尺寸小于该值,则使长度小于4001,因为这通常会更快。此外,NHibernate将懒惰地获取集合,但它可以一次获取所有项目。您可以进行分析以确定这是否具有任何性能影响。 (如果您只有少数几种语言,那么我怀疑您会发现不同之处。)如果您有多种语言(Say 50+),那么创建自定义属性以获取本地化文本可能是值得的。这些将发出查询以专门获取所需的文本。更重要的是,您可以在一个查询中获取给定实体的所有文本,而不是将每个本地化文本属性作为单独的查询。

请注意,只有在分析表明您有理由关注性能时才需要额外的努力。有可能本文中的实施将充分发挥作用。

答案 1 :(得分:1)

我只有Hibernate的经验,但是因为nHibernate非常相似:

一个选项是定义一个组件类型MultilingualString,其中包含每种语言的成员(假设编码时已知这组语言)。此类型也是通过语言ID为字符串放置getter的便捷位置。

class MultiLingualString {
    String english;
    String chinese;
    String klingon;

    String forLanguage(Language lang) {
        switch (lang) {
            // you can guess what goes here
        }
    }
}

这导致所有语言的字符串存储在数据库的单独列中,而对象世界中的表示保留了精细的粒度。

优点是不需要连接来获取字符串。另一方面,不使用这种方法获取字符串的唯一方法是使用投影,如果字符串很大,很多且很少需要,这是一个严重的限制。

如果你这么做,写一个UserType可能是值得的。

答案 2 :(得分:1)

从SQL Server的严格数据库角度来看,您应该拥有一个包含所有基本数据(记录密钥,日期,数字等)的表和一个包含所有可翻译字符串数据的表。让我们调用两个表Base和Base_Description。

Base确保每条记录都有一个密钥,密钥可能是字符串或自动生成的id,具体取决于您的特定用例。

Base_Description表与Base表相关,但也包含一个值,用于选择数据所在的语言。在我的项目中,我们使用sys.languages中的langid列,因为我们可以设置语言与连接,然后使用@@ LANGID获取大多数操作。

在我们的测试中,我们发现这比每种语言有多个字段要快得多,它还允许您更轻松地添加其他语言。我们还使用SQL Server全文索引,它完全适用于此方法。您应该使用中性语言进行索引,然后您可以选择要在运行时搜索的语言(也可以过滤Base_Description中的LangID列)。

答案 3 :(得分:1)

您的要求是否包含在同一对象中实际具有多语言属性的域对象?并且,如果是这样,是否存储在对象中的无限翻译(在集合中,比如说 - 在这种情况下我会说它需要像任何主/细节或父/子集合)或固定的翻译,其中案例语言(以及因此映射到存储过程或其他的结果)必须以静态方式确定?

在我工作的许多国际化应用程序中,数据只有一种语言 - 客户名称,产品名称(将一个国家使用的相同产品映射到另一个国家/地区的产品没有任何意义,它们都有不同的分销商和不同的SKU,当然还有本地化的定价)。界面也只有一种语言(一次)。因此,所有域对象一次只需要一种语言。因此,当对象被实例化时,将确定翻译的语言。

我们有翻译用户界面,允许用户更新翻译的文本,但这些只需要一次两种语言(本地和默认)。我可以看到这与你所说的最接近。我猜你会为每个可翻译的属性设置子集合,并在集合中包含所有可能的翻译。这可能与您链接的第三篇文章中的第二个解决方案最接近。当然,此时您还需要查看是否需要急切/延迟加载等。