实体框架核心-有效地在数据库中存储/查询多语言记录

时间:2019-06-03 00:21:10

标签: c# entity-framework-core

我正在构建一个必须支持多种语言的应用程序。

因此,我的数据库中的某些记录需要针对每种语言具有多个版本。

我将首先说明我目前是如何实现的:考虑一个名为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')

但是,据我所知,如果不使用RawQueryEF: Include with where clause),就不可能从Entity Framework Core本身完成此操作

因此产生了一个问题:是否有更好的方法使用EF Core在数据库中实现多语言记录?还是我应该继续我的方法,并希望EF Core在我的应用程序实际需要它的时候实现Include过滤(我承认我可能会过早地进行优化,但是我真的很好奇是否有一个实现这一目标的更好方法。

2 个答案:

答案 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");
    });
}
相关问题