Question

I working on a multilingual website (MVC 5, EF 6.1). To support multiple language for some fields I splitted my tables into 2 parts. One for language independent data and one for language dependent data.

For example my product tables are (simplified):

Product
 - Id int
 - Price float

ProductLang
 - ProductId int
 - LanguageId int
 - Name nvarchar
 - Desc nvarchar

So for the structure above I created 2 entity classes and a ModelBuilder mapping:

modelBuilder.Entity<ProductLang>().HasKey(t => new { t.ProductId,  t.LanguageId });

Everything works fine, EF created my database with fields above. At this point I little bit confused. What is the best way for CRUD operations?

How to query data? I just wrote this code below but I don't know if it was the best approach:

var test = context.Product.Select(t => new 
{ 
  Id         = t.Id, 
  Price      = t.Price, 
  Translated = t.ProductLang.Where(x => x.LanguageId == 1).FirstOrDefault(),

}).FirstOrDefault();

With this technique I can get values very simple:

Int32  id       = test.Id;
Double price    = test.Price;
String name     = test.Translated.Name;
String descr    = test.Translated.Descr;

How to create new record? My test code is:

Product product1 = new Product();
product1.Price = 3.99;

context.Product.Add(product1);

ProductLang translate1 = new ProductLang();

translate1.Language = language1;
translate1.Product = product1;
translate1.Name = "My First Product";

context.ProductLang.Add(translate1);

context.SaveChanges();

Codes above works fine but I'm not sure if this was the best way to deal with multilingual (split table) database structure. Is there any infrastructure in EF or in the FluentAPI to handle this more simple and better? There is any pattern or convention? Should I use an abstract base class to handle those operations if I had multiple translated table? Should I use generics here for any reasons?

Was it helpful?

Solution

Consider adding an additional layer of abstraction that shields the rest of the website from the physical structure used to represent the localized information.

For example, you could create a flat "Product" entity that would have the same structure regardless of whether it was localized or not. During query, map both tables (language-independent and localized) into that data structure:

var test = 
(
  from t in context.ProductLang
  where t.ProductId == 5 && t.Language = "en"
  select new Website.Model.Product
  {
    Id = t.Product.Id,
    Price = t.Product.Price,  // Language independent
    Name = t.Name             // Language dependent
  }
).SingleOrDefault();

If you wrap the code in a function or interface, your calling code can easily retrieve information without having to worry about how it's represented:

var test = DataService.GetProduct(5, "en");

Updating can work the same way. The trick there is that updates become a bit more difficult since you don't necessarily know whether or not to create the language-independent record or not. That makes the Update code a bit more complex - for complete thread-safety you'd have to use a transaction with locking. You may be able to get away with an "if statement" in your EF logic if updates to localized content are infrequent.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top