2009-02-11 86 views
1

我在我的數據庫中有狀態表以及包含這些狀態的語言特定版本的「本地化」表。主狀態表的要點是定義狀態ID值以及有關狀態的其他元數據。 「本地化」表是根據用戶的首選語言在用戶界面中顯示文本表示。下面是一個例子模式:LINQ to SQL中的數據庫數據的本地化/ I18n

create table [Language] 
(
    ID smallint primary key, 
    ISOName varchar(12) 
) 

create table EmployeeStatus 
(
    ID smallint primary key, 
    Code varchar(50) 
) 

create table EmployeeStatusLocalised 
(
    EmployeeStatusID smallint, 
    LanguageID smallint, 
    Description varchar(50), 
    constraint PK_EmployeeStatusLocalised primary key 
     (EmployeeStatusID, LanguageID), 
    constraint FK_EmployeeStatusLocalised_EmployeeStatus foreign key 
     (EmployeeStatusID) references EmployeeStatus (ID), 
    constraint FK_EmployeeStatusLocalised_Language foreign key 
     (LanguageID) references [Language] (ID) 
) 

create table Employee 
(
    ID int identity(1,1) primary key, 
    EmployeeName varchar(50) not null, 
    EmployeeStatusID smallint not null, 
    constraint FK_Employee_EmployeeStatus foreign key 
     (EmployeeStatusID) references EmployeeStatus (ID) 
) 

這是如何我通常訪問的數據:

select e.EmployeeName, esl.Description as EmployeeStatus 
from Employee e 
inner join EmployeeStatusLocalised esl on 
    e.EmployeeStatusID = esl.EmployeeStatusID and esl.LanguageID = 1 

我不是真的很高興,我的LINQ to SQL以最有效的方式做事,但是。這裏有一個例子:

using (var context = new MyDbDataContext()) 
{ 
    var item = (from record in context.Employees 
       select record).Take(1).SingleOrDefault(); 

    Console.WriteLine("{0}: {1}", item.EmployeeName, 
     item.EmployeeStatus.EmployeeStatusLocaliseds. 
      Where(esl => esl.LanguageID == 1).Single().Description); 
} 

回答

2

,我可能會留在數據庫中的employeeStatus碼和移動所有的定位邏輯到客戶端。如果這是一個Web應用程序(ASP.NET或ASP.NET MVC),那麼您將使用EmployeeStatus代碼作爲資源文件的關鍵字,然後使用UICulture =「Auto」和Culture =「Auto」來告訴ASP .NET根據「Accept-Language」HTTP Header獲取正確的資源。

您會提供默認(文化不敏感)資源嵌入您的應用程序,並允許satalite程序集覆蓋他們需要的默認值。

對於我來說,將數據本地化添加到數據庫中的問題在於,您首先會遇到更復雜的查詢,您必須繼續將語言環境抽入每個查詢中,並且無法緩存查詢如此廣泛。其次,您可以混合使用持有本地化實體和表格的表格。最後,需要DBA來完成本地化。

理想情況下,您希望有人瞭解如何翻譯文本以進行本地化,並讓他們使用他們熟悉的工具。那裏有許多.resx工具,以及允許語言專家「做他們的事」的應用程序。

如果你因數據庫本地化而陷入困境,因爲「事情就是這樣」,那麼你應該單獨查詢真實數據,然後在UI中加入這兩個數據庫。這至少會在未來爲您提供「升級路徑」給.RESX。

您應該國際化檢查蓋伊·史密斯,費里爾的書,如果你有興趣在這方面:

http://www.amazon.co.uk/NET-Internationalization-Developers-Guide-Building/dp/0321341384/ref=sr_1_1?ie=UTF8&s=books&qid=1239106912&sr=8-1

1

一種選擇是保持局部數據的緩存,使用類似的緩存應用程序塊或ASP.NET緩存,那麼就指的是緩存在視圖中。

這會限制數據庫調用的數量,因爲LINQ可能不需要加載狀態記錄來獲取本地化描述。

0

您可以在DataContext中使用LoadOptions,因此它會在初始查詢中加載數據。有些東西在線:

var options = new DataLoadOptions(); 
options.AssociateWith<Employee>(e=> 
    e.EmployeeStatus.EmployeeStatusLocaliseds 
    .Where(esl => esl.LanguageID == 1) 
    ); 
options.LoadWith<Employee>(e=>e.EmployeeStatus.EmployeeStatusLocaliseds); 

    using (var context = new MyDbDataContext()) 
    { 
     context.LoadOptions = options; 
     var item = (from record in context.Employees 
        select record).Take(1).SingleOrDefault(); 

     Console.WriteLine("{0}: {1}", item.EmployeeName, 
      item.EmployeeStatus.EmployeeStatusLocaliseds 
      .Single().Description 
     ); 
    } 

另一方面,狀態可能是非常靜態的數據,所以緩存它們會非常有效。如果您堅持生成的實體,則可以在使用緩存的部分Employee類中定義一個屬性。

0

旁白:在這種情況下,我會考慮處理狀態代碼(而不是ID)作爲主鍵,並有CodeEmployee規格化;這保留了外鍵,但減少了所需的連接和導航的數量。它還使您可以將代碼映射到.NET代碼中的enum

我可能會使用i18n文本值的緩存(按需)緩存;這樣的:

  • 最大限度地減少了查詢的複雜
  • 最大限度地減少數據吞吐量/ IO
  • 最小化對象標識/更改的開銷跟蹤
  • 最大限度地減少「materializations」正在不斷髮生
  • 的數量可以讓你以針對對象模型中的枚舉進行編程,但顯示國際文本
  • 摘要i18n的實現(所以你可以切換到resx或類似的如果你需要,或自動轉換你可以在不受限於現有數據查詢的情況下獲得i18n值 - 即填充搜索屏幕的下拉框(與個別員工無關,因此示例查詢不會幫助)

我猜i18n數據緩慢變化,所以緩存方法是理想的。

我會加載所有相關串一次一個語言 - 所以第一次是必要的威爾士狀態(例如),我會加載所有狀態字符串威爾士和高速緩存反對該語言的標準代碼(cy)。

,讓視圖代碼更簡單,可以考慮使用員工的擴展方法(在UI級):

public static class EmployeeExtensions { 
    public static string GetStatusText(this Employee emp) { 
     /* do your funky thing, presumably using the HttpContext or 
     some other thread-static value to resolve the current culture */ 
    } 
} 

那麼在你看來,你可以使用:

<%=emp.GetStatusText()%> 

等。不幸的是,沒有擴展屬性,但是通過一種方法,您還可以選擇將語言代碼傳遞到方法中(添加參數之後):

<%=emp.GetStatusText(lang)%> 
0

我發現我們的方案很好的解決方案。

'設計' 是這樣:

  1. 創建一個名爲 'GlobalizedString' 與PK ID表。
  2. 創建一個名爲「LocalizedString」表與參考上面和下面的字段:
    • CultureId(參照一些文化查找表)
    • 含量(這將是在上面的語言的字符串)

在GlobalizedString,添加一個名爲 '內容' 屬性(注意,這通過LINQ2SQL不可查詢,但在LINQ2Objects作品),看起來像:

public string Content 
{ 
    get { return LocalizedStrings.Single( 
      x => x.Culture.CultureCode == 'my current CultureInfo's code'); } 
    set { /* exercise for reader */ } 
} 

因此,不是使用nvarchar列,而是指向GlobalizedString表。

現在,而不是你正常的「邏輯」(例如結合),您只需指GlobalizedString的內容屬性來獲取當前語言:)

正如前文所說的內容,該內容屬性不起作用在Linq2SQL上,我仍然在尋找一種簡單的方法來實現這一點(歡迎提出建議)。

否則,系統將親自爲我們服務好:)