NHibernate:通过基于用户文化交换列进行本地化
我读过关于NHibernate本地化的文章,但似乎没有什么东西非常适合这种情况。我们的数据库使用以下模式存储本地化信息:NHibernate:通过基于用户文化交换列进行本地化,nhibernate,fluent-nhibernate,localization,nhibernate-mapping,Nhibernate,Fluent Nhibernate,Localization,Nhibernate Mapping,我读过关于NHibernate本地化的文章,但似乎没有什么东西非常适合这种情况。我们的数据库使用以下模式存储本地化信息: TABLE NAME: PRODUCT COLUMNS: ID PRODUCT_CODE PRODUCT_NAME DESCRIPTION1 DESCRIPTION2 DESCRIPTION3 字段DESCRIPTION1、DESCRIPTION2和DESCRIPTION3包含产品的本地化描述。始终只有三个本地化字符串,并且数字始终表示相同的区域性(例如,3是英语)。在其
TABLE NAME: PRODUCT
COLUMNS:
ID
PRODUCT_CODE
PRODUCT_NAME
DESCRIPTION1
DESCRIPTION2
DESCRIPTION3
字段DESCRIPTION1、DESCRIPTION2和DESCRIPTION3包含产品的本地化描述。始终只有三个本地化字符串,并且数字始终表示相同的区域性(例如,3是英语)。在其他一些表中,我们有像NAME1、NAME2和NAME3这样的列
我希望使用(Fluent)NHibernate映射到这些列,这样模型类将只包含一个名为“Description”的属性,并且它将包含根据当前线程的区域性从正确字段获得的值。NHibernate似乎有多个扩展点,但哪一个是最好的
将字符串属性动态映射到正确的列?
在我的梦境中,我会将描述字段作为字符串
public class Product
{
/* ... */
public virtual string Description { get; set; }
}
在类映射中,我会告诉Fluent NHibernate在运行时计算正确的列名:
public class ProductMap : ClassMap<Product>
{
public ProductMap()
{
/* ... */
MapAsLocalized(x => x.Description);
}
}
然后获取本地化值,例如:
public class Product
{
/* ... */
public virtual LocalizedString Description { get; set; }
}
// Product prod;
// Get product from db
Console.WriteLine(prod.Description.Value);
在LocalizedString示例中,开发人员仍然可以创建映射,而无需创建到每个描述列的映射:
public class ProductMap : ClassMap<Product>
{
public ProductMap()
{
/* ... */
Map(x => x.Description);
}
}
公共类ProductMap:ClassMap
{
公共产品地图()
{
/* ... */
映射(x=>x.Description);
}
}
当使用此映射执行查询时,它将返回LocalizedString(内部是某种类型的集合)中的DESCRIPTION1、DESCRIPTION2和DESCRIPTION3的值
关于如何实施解决方案1或解决方案2有何建议?或者两者都可以?而NHibernate确实提供了在运行时修改映射的工具。每次需要执行查询时,NHibernate都要重建会话工厂,这将严重影响性能。我建议使用你的第二个想法。您甚至不需要自定义IUserType。可以将其映射为组件
Component(x => x.Description, c =>
{
c.Map(d => d.Description1);
...
});
或者,您可以将这些描述映射到产品类中的支持字段,并提供公共描述属性,该属性在运行时选择适当的字段。您可以使用用户类型
public class LocalizationUserType : ImmutableUserType
{
public override object NullSafeGet(IDataReader rs, string[] names, object owner)
{
switch(Languageprovider.GetLanguage())
{
case language1:
return NHibernateUtil.String.NullSafeGet(cmd, value, index);
case language2:
return NHibernateUtil.String.NullSafeGet(cmd, value, index + 1);
...
}
return null;
}
public override void NullSafeSet(IDbCommand cmd, object value, int index)
{
switch(Languageprovider.GetLanguage())
{
case language1:
NHibernateUtil.String.NullSafeSet(cmd, value, index);
break;
case language2:
NHibernateUtil.String.NullSafeSet(cmd, value, index + 1);
break;
...
}
}
public override Type ReturnedType
{
get { return typeof(String); }
}
public override SqlType[] SqlTypes
{
get { return new[]
{
SqlTypeFactory.GetString(1000),
SqlTypeFactory.GetString(1000),
SqlTypeFactory.GetString(1000),
}; }
}
}
ImmutableUserType是一个基类,实现了一些IUserType方法。如果你愿意,我可以发送实现
使用方法:
public class ProductMap : ClassMap<Product>
{
ProductMap
{
...
Map(p => p.Name)
.Columns.Add("name1", "name2", "name3")
.CustomType<LocalizationUserType>();
...
Map(p => p.Description)
.Columns.Add("desc1", "desc2", "desc3")
.CustomType<LocalizationUserType>();
公共类ProductMap:ClassMap
{
产品地图
{
...
映射(p=>p.Name)
.列。添加(“名称1”、“名称2”、“名称3”)
.CustomType();
...
映射(p=>p.Description)
.列。添加(“说明1”、“说明2”、“说明3”)
.CustomType();
我能给出的唯一建议(无用)是修复DB模式。您如何在当前设计中添加另一种语言?不幸的是,我们的数据库是一个遗留的数据库,可以追溯到近20年前。您是否大量使用投影?这将影响解决方案。