查询友好域对象本地化

本文关键字:对象 本地化 查询 | 更新日期: 2023-09-27 18:28:56

我需要设计一个存储部分多语言内容的应用程序;即一些域对象字段是可翻译的。注意:我使用的是NHibernate,但这只是本例中的一个技术细节。

让我们考虑以下域模型:

public class Post {
    public virtual int Id {get; set;}
    public virtual User Author {get; set;}
    public virtual string Title {get; set;} // translatable
    public virtual string Content {get; set;}  // translatable
}

浏览互联网,我发现了几种方法,其中大多数都很粗糙和丑陋;许多人完全不能接受。大多数解决方案都是基于在模型中引入"特殊"字段,无论是像Title_FR, Content_FR, Title_EN, Content_EN还是Dictionary<string, string> ContentTranslations

优点:

  • 易于查询(第一种情况)
  • 性能

缺点:

  • 添加语言时需要更改模式(第一种情况)
  • 需要向模型中添加特殊字段

后来,我设计了自己的解决方案(经过进一步调查,碰巧是在重新发明轮子),它拦截了NHibernate特定的事件;即,一旦用值填充了域模型的实例,就用来自抽象翻译提供者的翻译值重新填充可翻译字段。

优点:

  • 无缝集成
  • 没有架构修改
  • 完全自动

缺点:

  • 无法查询翻译字段;对已翻译字段进行过滤会导致奇怪的(从用户的角度来看)行为

我正在寻找

  1. 可能无缝集成。域模型中未引入特殊字段
  2. 自动应用翻译
  3. 更新(翻译的)域对象时注意不要覆盖原始值
  4. 查询友好;即该机制的引入不需要显著地改变LINQ查询。这可能会取消"可加入"翻译表的资格
  5. 理想情况下,解决方案不应破坏LINQ投影;然而,这可能只是要求太高了(*)

(*)5日的解释词。我广泛使用AutoMapper的Project.To(),以避免检索不必要的字段和SELECT N+1问题。我提出的解决方案不适用于投影,我相信使用投影时不会触发OnPostLoad事件

有关于这个主题的推荐读物吗?

查询友好域对象本地化

我不确定您的DB结构是什么样子的。如果您不想使用IDictionary(我更喜欢),那么我建议实现一个LocalizableString类和相应的ICompositeUserTypeIUserType,或者使用组件映射。

public class Post {
    public virtual int Id {get; set;}
    public virtual User Author {get; set;}
    public virtual LocalizableString Title {get; set;} // translatable
    public virtual LocalizableString Content {get; set;}  // translatable
}

您可能还需要实现linq提供程序的一些扩展,以允许自定义查询操作。


需要考虑的一些替代方法:

  • 使用公式列本地化字段的公式列
  • 使用我自己的DelegateDecompiler来允许查询计算的属性