我正在构建一个必须支持多种语言的应用程序。
因此,我的数据库中的某些记录需要针对每种语言具有多个版本。
我将首先说明我目前是如何实现的:考虑一个名为Region
的实体,该实体代表地理位置,并且仅具有名称。
我会这样设计我的实体:
public class Region
{
public int Id { get; set; }
public List<RegionLanguage> Languages { get;set; }
}
public class RegionLanguage
{
public Region Region { get;set; } // Parent record this language applies to
public string CultureCode { get; set; } // Will store culture code such as en-US or fr-CA
// This column/property will be in the language specified by Culturecode
[StringLength(255)]
public string Name { get;set; }
}
从数据库角度看,这非常有效,因为它可以无限扩展到任意数量的记录。但是,由于Entity Framework Core的工作方式,它的可伸缩性降低了。
使用上述结构,我可以查询Region
并根据特定的区域性信息生成视图模型:
var region = _context.Regions.Where(e => e.Id == 34)
.Include(e => e.Languages)
.FirstOrDefault();
var viewModel = new RegionViewModel
{
Name = region.Languages.FirstOrDefault(e => e.CultureCode == "en-US")?.Name // en-US would be dynamic based on the user's current language preference
}
您可以看到这变得效率低下,因为当我实际上只需要一个实体然后在内存中搜索正确的语言时,我必须包括要获取的实体的所有语言记录。当然,当我需要获取Regions
列表然后必须返回大量不必要的数据时,情况变得更糟。
当然,只需在join
语句上添加一个额外的子句,即可直接使用SQL来实现:
select *
from Regions
left join RegionLanguage on (RegionLanguage.Region = Regions.Id and RegionLanguage.CultureCode = 'en-US')
但是,据我所知,如果不使用RawQuery
(EF: Include with where clause),就不可能从Entity Framework Core本身完成此操作
因此产生了一个问题:是否有更好的方法使用EF Core在数据库中实现多语言记录?还是我应该继续我的方法,并希望EF Core在我的应用程序实际需要它的时候实现Include
过滤(我承认我可能会过早地进行优化,但是我真的很好奇是否有一个实现这一目标的更好方法。
答案 0 :(得分:0)
您可以使用投影。
var languageRegion = await _context.Regions
.Select(p => new Region
{
Languages = p.Languages.FirstOrDefault(e => e.CultureCode == "en-US")
}.FirstOrDefaultAsync(e => e.Id == 34);
如果区域和语言不经常更改,则可以使用缓存。
答案 1 :(得分:0)
您可以使用Global Query Filter
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<RegionLanguage>(builder =>
{
builder.HasQueryFilter(rl => rl.CultureCode == "en-US");
});
}