用动态属性替换linq select中的条件运算符

qv7cva1a  于 2022-12-06  发布在  其他
关注(0)|答案(2)|浏览(152)

此linq查询带有条件运算符:

public List<ClientDto> GetClients(string locale)
{
    var q = from c in _dbContext.Clients
    select new ClientDto
    {
        Id = c.Id,
        Name = locale == "en" ? v.Name_en : v.Name_de
    };
    return q.ToList()
}

将生成正确的SQL查询,只选择我需要的字段,而不需要额外的:

SELECT c."Id", c."Name_en" AS "Name" FROM "Clients" AS c

我怎样才能做到同样的事情并支持多种语言呢?条件操作符似乎是不可能的。类似于:

select new ClientDto
{
    Id = c.Id,
    Name = getNameProp(language)
};

但是没有从数据库中获取所有字段的副作用。只要我将c作为参数发送给另一个函数(getNameProp(language,c)),生成的查询就会返回数据库中的所有字段。
当然,我可以重新构建数据库,并将可翻译的字符串保存在单独的表中,但问题的关键在于linq部分,该解决方案可能对其他目的有用。

cmssoen2

cmssoen21#

我建议使用LINQKit,它只需要配置DbContextOptions

builder
    .UseSqlServer(connectionString)
    .WithExpressionExpanding(); // enabling LINQKit extension

定义帮助器类:

public static class LanguageExtensions
{
    public static Expression<Func<T, string>> NameGetter<T>(string language) 
    {
        var param = Expression.Parameter(typeof(T), "e");

        // simple realization
        var propName = "Name_" + language;

        var body = Expression.PropertyOrField(param, propName);

        return Expression.Lambda<Func<T, string>>(body, param);
    }
}

然后可以按以下方式使用helper:

public List<ClientDto> GetClients(string locale)
{
    var q = from c in _dbContext.Clients
    select new ClientDto
    {
        Id = c.Id,
        Name = LanguageExtensions.NameGetter<Client>(language).Invoke(e)
    };
    return q.ToList()
}
wgxvkvu9

wgxvkvu92#

在Linq-To-Objects中,您可以为每种语言使用不同的getterFunc将其参数化,因此您的查询始终只知道一个字段名,例如

var nameGetter = NameGetter("en");
var clientList = GetClients(nameGetter);

public List<ClientDto> GetClients(Func<Client, string> nameGetter) {
    var q = from c in _dbContext.Clients
    select new ClientDto {
       Id = c.Id,
       Name = nameGetter(c)
    };
    return q.ToList()
}

public Func<Client, string> NameGetter(string language) {
     Func<Client, string> getter = language switch {
                   "en" => c => c.Name_en,
                   "de" => c => c.Name_de,
                   "fr" => c => c.Name_fr
                    ...
                   _ => default,
     };
    return getter;
}

但是我不确定您的Linq-To-myOrm-Provider实现是否以及如何将其转换为SQL...

相关问题