1

我已閱讀關於NHibernate本地化的few good articles,但似乎沒有很好地適合這種情況。我們的DB存儲以下模式的本地化信息:NHibernate:通過根據用戶文化交換列進行本地化

TABLE NAME: PRODUCT 
COLUMNS: 
ID 
PRODUCT_CODE 
PRODUCT_NAME 
DESCRIPTION1 
DESCRIPTION2 
DESCRIPTION3 

字段DESCRIPTION1,DESCRIPTION2和DESCRIPTION3包含產品的本地化描述。總是有三個本地化的字符串,數字總是指相同的文化(例如3是英語)。在其他一些表中,我們有NAME1,NAME2和NAME3這樣的列。

我想使用(流利)NHibernate以這樣的方式映射到這些列:模型類將只包含一個名爲「Description」的屬性,它將包含從正確的字段獲取的值,基於當前線程的文化。 NHibernate似乎有多個擴展點,但哪個最好?

將字符串屬性動態映射到正確的列?

在我的夢想世界中,我將Description字段作爲字符串。

public class Product 
{ 
    /* ... */ 

    public virtual string Description { get; set; } 
} 

而在類映射我會以某種方式告訴流利的NHibernate正確的列名在運行時評價:

public class ProductMap : ClassMap<Product> 
{ 
    public ProductMap() 
    { 
     /* ... */ 

     MapAsLocalized(x => x.Description); 
    } 
} 

當一個查詢與此映射執行,我會自動喜歡我的代碼檢查線程的文化,並根據它選擇一個正確的列。例如,如果文化是en-US,則查詢將從DESCRIPTION3-列中獲取值到Description-屬性中。

自定義IUSERTYPE?

但是,如果這不可能,我可以解決一個自定義LocalizedString級,這將允許我來定義產品類是這樣的:

public class Product 
{ 
    /* ... */ 

    public virtual LocalizedString Description { get; set; } 
} 

,然後得到例如像這樣的本地化值:

 // Product prod; 
     // Get product from db 

     Console.WriteLine(prod.Description.Value); 

在LocalizedString-例的構思是,dev的仍然可以創建地圖,而不必創建映射到每一個說明柱:

public class ProductMap : ClassMap<Product> 
{ 
    public ProductMap() 
    { 
     /* ... */ 

     Map(x => x.Description); 
    } 
} 

而且,當使用此映射執行查詢時,它會在LocalizedString(它在內部是某種類型的集合)內返回DESCRIPTION1,DESCRIPTION2和DESCRIPTION3的值。

有關如何實施解決方案1或解決方案2的任何建議?甚至兩個?

+0

唯一的建議(沒用)我可以給是修復DB模式:如果你想

和使用我公司可以派實施。你會如何在當前的設計中添加另一種語言? – 2011-05-05 19:26:36

+0

不幸的是,我們的數據庫是一個遺留問題,可追溯到近20年。 – 2011-05-12 07:21:46

+0

您是否大量使用投影?這將影響解決方案。 – 2011-05-18 15:43:01

回答

2

你可以用一個用戶類型

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>(); 
0

雖然NHibernate確實提供了一個工具來修改映射在運行時。這會嚴重阻礙NHibernate在每次想要執行查詢時重建會話工廠的性能。我會建議使用你的第二個想法。你甚至不需要一個自定義的IUserType。您可以將其映射爲組件。

Component(x => x.Description, c => 
    { 
      c.Map(d => d.Description1); 
      ... 
    }); 

或者,您可以將每個描述映射到Product類中的後臺字段,並提供公共的Description屬性,以在運行時選擇適當的字段。