查询友好域对象本地化
本文关键字:对象 本地化 查询 | 更新日期: 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特定的事件;即,一旦用值填充了域模型的实例,就用来自抽象翻译提供者的翻译值重新填充可翻译字段。
优点:
- 无缝集成
- 没有架构修改
- 完全自动
缺点:
- 无法查询翻译字段;对已翻译字段进行过滤会导致奇怪的(从用户的角度来看)行为
我正在寻找
- 可能无缝集成。域模型中未引入特殊字段
- 自动应用翻译
- 更新(翻译的)域对象时注意不要覆盖原始值
- 查询友好;即该机制的引入不需要显著地改变LINQ查询。这可能会取消"可加入"翻译表的资格
- 理想情况下,解决方案不应破坏LINQ投影;然而,这可能只是要求太高了(*)
(*)5日的解释词。我广泛使用AutoMapper的Project.To()
,以避免检索不必要的字段和SELECT N+1问题。我提出的解决方案不适用于投影,我相信使用投影时不会触发OnPostLoad
事件
有关于这个主题的推荐读物吗?
我不确定您的DB结构是什么样子的。如果您不想使用IDictionary(我更喜欢),那么我建议实现一个LocalizableString
类和相应的ICompositeUserType
、IUserType
,或者使用组件映射。
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来允许查询计算的属性