【问题标题】:Entity Splitting For One-To-Many table relationships一对多表关系的实体拆分
【发布时间】:2014-07-16 08:07:53
【问题描述】:

在这篇文章 (What are best practices for multi-language database design?) 之后,我将所有数据库表拆分为两个:第一个表仅包含与语言无关的数据(主键等),第二个表包含每种语言的一条记录,其中包含本地化数据加上语言的 ISO 代码。两个表之间的关系是一对多的。 这里是数据模型的截图:https://dl.dropboxusercontent.com/u/17099565/datamodel.jpg

因为网站有 8 种语言,对于表“CourseCategory”中的每条记录,我在表“CourseCategoryContents”中有 8 条记录。 “Course”和“CourseContent”也是如此

然后我使用实体拆分以便只有一个实体用于课程类别,一个实体用于课程:

public class CourseCategoryConfiguration : EntityTypeConfiguration<WebCourseCategory>
      {
          public CourseCategoryConfiguration()
          {
              Map(m =>
              {
                  m.Properties(i => new { i.Id, i.Order, i.Online });
                  m.ToTable("CourseCategories");
              });

              Map(m =>
              {
                  m.Properties(i => new { i.LanguageCode, i.Name, i.Permalink, i.Text, i.MetaTitle, i.MetaDescription, i.MetaKeywords });
                  m.ToTable("CourseCategoryContents");
              });
          }
      }

      public class CourseConfiguration : EntityTypeConfiguration<WebCourse>
      {
          public CourseConfiguration()
          {
              Map(m =>
              {
                  m.Properties(i => new { i.Id, i.CategoryId, i.Order, i.Label, i.ThumbnailUrl, i.HeaderImageUrl });
                  m.ToTable("Courses");
              });

              Map(m =>
              {
                  m.Properties(i => new { i.LanguageCode, i.Name, i.Permalink, i.Text, i.MetaTitle, i.MetaDescription, i.MetaKeywords, i.Online });
                  m.ToTable("CourseContents");
              });
          }
      }

然后用所需的语言检索课程,包括它们的类别,我这样做:

using (WebContext dbContext = new WebContext())
{
  // all courses of all categories in the desired language
          return dbContext.Courses
              .Include(course => course.Category)
              .Where(course => course.LanguageCode == lan
                     && course.Category.LanguageCode == lan)
              .ToList();
      }
}

实体拆分适用于一对一关系,但这里我有一对多关系。

该网站有 3 种语言(“en”、“de”、“fr”)的内容(CourseCategories 和 Courses)。 EF 以正确的语言(例如英语)正确返回所有课程及其类别,但每条记录返回 3 次。这是因为我也有 3 种语言的 CourseCategory。

我想出的唯一一个可行的解决方案是避免使用“.Include(Category)”,首先以所需语言获取所有课程,然后在 foreach 循环中,为每个课程检索其语言类别。我不喜欢这种延迟加载的方式,我想一次性检索所有需要的数据。

谢谢!

【问题讨论】:

    标签: linq entity-framework split entity multilingual


    【解决方案1】:

    最好的解决方案是将表映射到模型,因为它在您的模型 Course 类中将具有导航属性 ICollection&lt;CourseCategoryContent&gt;。

    在这种情况下,您只需“根据您的应用程序设计”将此模型投影到 DTO 或 ViewModel

    例如 您的模型将如下所示

    public class Course
    {
        public int Id {get; set;}
        public int Order {get; set;}
        public ICollection<CourseCategoryContent> CourseCategoryContents {get; set;}
    }
    
    public class CourseCategoryContent
    {
        public string LanguageId {get; set;}
        public string Name {get; set;}
    }
    

    然后像这样创建新的 DTO 或 ViewModel:

    public class CourseDTO
    {
        public int Id {get; set;}
        public int Order {get; set;}
        public string Name {get; set;}
    }
    

    最后做投影

    public IQueryable<CourseDTO> GetCourseDTOQuery ()
    {  
        return dbContext.Courses.Select(x=>new CourseDTO{
        Id = x.Id,
        Order = x.Order,
        Name = x.CourseCategoryContents.FirstOrDefault(lang => lang.LanguageId == lang).Name,
        });      
    } 
    

    请注意,返回类型是 IQueryable,因此您可以在访问数据库之前对其进行任何过滤、排序或分组操作。

    希望这有帮助

    【讨论】:

      【解决方案2】:

      恐怕没有万能的答案,每一种方式都有妥协。

      我在相当大的项目中同时使用了数据库方法(10+ 种语言相关的表)和资源文件方法,如果数据是静态的并且不会改变(即您不收取不同的价格或其他任何东西) ) 我肯定会考虑从您的数据库模型中抽象出语言并使用资源键然后从文件中加载您的数据。

      原因或这是您现在遇到的无法过滤包含的问题(这可能在 EF6 中发生了变化?我知道它在要做的事情列表中)。您可能可以像您正在做的那样将其读入内存并过滤它们,但这意味着它对我们来说性能不是很好,我必须编写存储过程,我刚刚通过了 iso 语言并在 EF 中执行.

      从维护的角度来看,它也更容易,对于数据库项目,我必须编写一个管理控制台,以便人们可以登录并编辑不同语言的值等。使用资源文件,我只是将值复制粘贴到excel 并将它们通过电子邮件发送给我们用来翻译的人。

      这取决于您的项目的复杂性和您喜欢什么,我将来仍然会考虑这两种方法。

      TLDR:我发现的选项是:

      1) 在内存中过滤 2) 带过滤器的延迟加载 3) 将存储过程写入 EF 并映射该结果 4) 改用资源

      希望对你有帮助

      编辑:查看图表后,您可能需要搜索与语言相关的值?在这种情况下,资源可能不起作用。如果您只是让他们离开菜单,那么您就可以开始了。

      【讨论】:

        猜你喜欢
        • 2013-08-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-24
        • 1970-01-01
        • 2016-07-01
        • 2017-06-27
        相关资源
        最近更新 更多