Best Practices to localize entities with EF Code first

前端 未结 1 1320
无人及你
无人及你 2020-12-14 05:04

I am developing a domain model using EF Code First to persist the data. I have to add support for multilanguage and I would like not to contaminate the domain model with loc

相关标签:
1条回答
  • 2020-12-14 05:28

    Here is what I use and works well with code first.

    Define a base Translation class:

    using System;
    
    public abstract class Translation<T> where T : Translation<T>, new()
    {
    
      public Guid Id { get; set; }
    
      public string CultureName { get; set; }
    
      protected Translation()
      {
        Id = Guid.NewGuid();
      }
    
    }
    

    Define a TranslationCollection class:

    using System.Collections.ObjectModel;
    using System.Globalization;
    using System.Linq;
    
    public class TranslationCollection<T> : Collection<T> where T : Translation<T>, new()
    {
    
      public T this[CultureInfo culture]
      {
        get
        {
          var translation = this.FirstOrDefault(x => x.CultureName == culture.Name);
          if (translation == null)
          {
            translation = new T();
            translation.CultureName = culture.Name;
            Add(translation);
          }
    
          return translation;
        }
        set
        {
          var translation = this.FirstOrDefault(x => x.CultureName == culture.Name);
          if (translation != null)
          {
            Remove(translation);
          }
    
          value.CultureName = culture.Name;
          Add(value);
        }
      }
    
      public T this[string culture]
      {
        get
        {
          var translation = this.FirstOrDefault(x => x.CultureName == culture);
          if (translation == null)
          {
            translation = new T();
            translation.CultureName = culture;
            Add(translation);
          }
    
          return translation;
        }
        set
        {
          var translation = this.FirstOrDefault(x => x.CultureName == culture);
          if (translation != null)
          {
            Remove(translation);
          }
    
          value.CultureName = culture;
          Add(value);
        }
      }
    
      public bool HasCulture(string culture)
      {
        return this.Any(x => x.CultureName == culture);
      }
    
      public bool HasCulture(CultureInfo culture)
      {
        return this.Any(x => x.CultureName == culture.Name);
      }
    
    }
    

    You can then use those classes in your entities, e.g.:

    using System;
    using System.Globalization;
    
    public class HelpTopic
    {
    
      public Guid Id { get; set; }
    
      public string Name { get; set; }
    
      public TranslationCollection<HelpTopicTranslation> Translations { get; set; }
    
      public string Content
      {
        get { return Translations[CultureInfo.CurrentCulture].Content; }
        set { Translations[CultureInfo.CurrentCulture].Content = value; }
      }
    
      public HelpTopic()
      {
        Id = Guid.NewGuid();
        Translations = new TranslationCollection<HelpTopicTranslation>();
      }
    
    }
    

    With HelpTopicTranslation defined as:

    using System;
    
    public class HelpTopicTranslation : Translation<HelpTopicTranslation>
    {
    
      public Guid Id { get; set; }
    
      public Guid HelpTopicId { get; set; }
    
      public string Content { get; set; }
    
      public HelpTopicTranslation()
      {
        Id = Guid.NewGuid();
      }
    
    }
    

    Now, for the code first specific side of things, use the following configuration:

    using System.Data.Entity.ModelConfiguration;
    using Model;
    
    internal class HelpTopicConfiguration : EntityTypeConfiguration<HelpTopic>
    {
    
      public HelpTopicConfiguration()
      {
        Ignore(x => x.Content); // Ignore HelpTopic.Content since it's a 'computed' field.
        HasMany(x => x.Translations).WithRequired().HasForeignKey(x => x.HelpTopicId);
      }
    
    }
    

    And add it to your context configurations:

    public class TestContext : DbContext
    {
    
      public DbSet<HelpTopic> HelpTopics { get; set; }
    
      protected override void OnModelCreating(DbModelBuilder modelBuilder)
      {
        modelBuilder.Configurations.Add(new HelpTopicConfiguration());
      }
    
    }
    

    When all of this is done, the following migration is generated:

    using System.Data.Entity.Migrations;
    
    public partial class AddHelpTopicTable : DbMigration
    {
    
      public override void Up()
      {
        CreateTable(
          "dbo.HelpTopics",
          c => new
          {
            Id = c.Guid(false),
            Name = c.String(),
          })
          .PrimaryKey(t => t.Id);
    
        CreateTable(
          "dbo.HelpTopicTranslations",
          c => new
          {
            Id = c.Guid(false),
            HelpTopicId = c.Guid(false),
            Content = c.String(),
            CultureName = c.String(),
          })
          .PrimaryKey(t => t.Id)
          .ForeignKey("dbo.HelpTopics", t => t.HelpTopicId, true)
          .Index(t => t.HelpTopicId);
      }
    
      public override void Down()
      {
        DropForeignKey("dbo.HelpTopicTranslations", "HelpTopicId", "dbo.HelpTopics");
        DropIndex("dbo.HelpTopicTranslations", new[] { "HelpTopicId" });
        DropTable("dbo.HelpTopicTranslations");
        DropTable("dbo.HelpTopics");
      }
    
    }
    

    Any comments and/or improvements are welcome...

    0 讨论(0)
提交回复
热议问题