在本文(What are best practices for multi-language database design?)之后,我将我的所有数据库表分成两部分:第一个表只包含与语言无关的数据(主键等)。第二个表包含每种语言的一条记录,包含本地化数据和语言的ISO代码。这两个表之间的关系是一对多的。这里是数据模型的屏幕截图:https://dl.dropboxusercontent.com/u/17099565/datamodel.jpg
因为该网站有8种语言,所以表"CourseCategory“中的每条记录我都有8条表"CourseCategoryContents”中的记录。“课程”和"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和课程)。EF以正确的语言正确地返回所有课程及其类别(例如。),但每次返回记录3次。这是因为我也有3种语言的CourseCategory。
我想出的唯一有效解决方案是避免使用“.Include(类别)”,首先以所需的语言获取所有课程,然后,在一个预先的周期中,为每个课程检索其语言类别。我不喜欢这种懒散的加载方法,我想一次检索所有想要的数据。
谢谢!
发布于 2014-07-16 13:34:49
最好的解决方案是将表映射到模型,因为在模型Course类中将有一个导航属性ICollection<CourseCategoryContent>。
在这种情况下,您只需“根据您的应用程序设计”将此模型投影到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,因此您可以在访问数据库之前对其执行任何筛选、排序或分组操作。
希望这能帮上忙
发布于 2014-07-16 11:31:07
恐怕没有解决所有问题的办法,每个办法都有妥协的余地。
我在相当大的项目中使用了数据库方法(10+语言相关表)和资源文件方法,如果数据是静态的,并且不会改变(即您不会收取不同的价格或其他任何东西),我肯定会考虑将语言从数据库模型中抽象出来,然后使用资源键从文件中加载数据。
原因或这是您现在遇到的问题,您不能过滤包含(这可能在EF6中已经改变了?我知道这在要做的事情清单上)。你也许可以像你正在做的那样,把它读入内存并过滤它们,但这意味着它对我们来说不是很好的表现,我不得不编写存储过程,我刚刚通过了iso语言并在EF中执行。
从维护的角度来看,对于DB项目来说,我必须编写一个管理控制台,以便人们可以登录和编辑不同语言的值等等。使用资源文件,我只需复制粘贴到excel中的值,并将它们发送给我们用来翻译的人。
这取决于项目的复杂性和您喜欢什么,我在将来仍然会考虑这两种方法。
TLDR:我发现的选项是:
( 1)内存中的过滤( 2)带有过滤器的延迟加载( 3)将存储过程写到EF并映射结果( 4)使用资源
希望这能有所帮助
编辑:在看了图表之后,你可能需要针对语言依赖的值进行搜索吗?在这种情况下,资源可能无法工作。如果你只是让他们离开菜单,那你就可以走了。
https://stackoverflow.com/questions/24775446
复制相似问题