LINQ - 如果它们存在则选择它们,否则回退到这些

Kje*_*sen 8 c# linq

想想存储在这个表中的本地化文本:

表格文本

  • TEXTID
  • 语言

现在我想为TextId 1选择一个文本.如果"Danish"中没有这个TextId的文本,我想回到"英语".

我可以这样做:

var texts = MyDb.Texts.Where(x=>x.TextId == 1 & x.Language == "Danish");

if (!texts.Any()){
    texts = MyDb.Texts.Where(x=>x.TextId == 1 & x.Language == "English");
}
Run Code Online (Sandbox Code Playgroud)

...但是我必须重复Where子句的其余部分,这意味着我正在重复自己(在这个例子中不是那么糟糕,但可能会有更多的条款).

有更简单的方法吗?

Ric*_*001 9

我建议使用Filter模式,在其中编写针对IEnumerable的扩展方法.这样,您的大部分逻辑都被封装到您可以反复使用的方法中:

public static class TextExtensions
    {
        [System.Runtime.CompilerServices.Extension]
        public static IEnumerable<Text> ByTextId(this IEnumerable<Text> qry, int textId)
        {
            return qry.Where(t => t.TextId == textId);
        }

        [System.Runtime.CompilerServices.Extension]            
        public static IEnumerable<Text> ByLanguage(this IEnumerable<Text> qry, string language)
        {
            return qry.Where(t => t.Language == language);
        }
    }
Run Code Online (Sandbox Code Playgroud)

然后你的代码变成:

var texts = MyDB.Texts.ByTextId(1).ByLanguage("Danish");
Run Code Online (Sandbox Code Playgroud)

然后重复变成无问题.我还建议让自己成为一个静态类来保存各种语言值以避免硬编码:

public static class LanguageValues
{
    public static string English
    {
        get
        {
            return "English";
        }
    }

    public static string Danish
    {
        get
        {
            return "Danish";
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你的代码变成:

var texts = MyDB.Texts.ByTextId(1).ByLanguage(LanguageValues.Danish);
Run Code Online (Sandbox Code Playgroud)

您可以将它与DefaultIfEmpty方法结合使用,该方法为您提供:

var texts = MyDB.Texts.DefaultIfEmpty(MyDB.Texts.ByTextId(1).ByLanguage(LanguageValues.English).Single()).ByTextId(1).ByLanguage(LanguageValues.Danish);
Run Code Online (Sandbox Code Playgroud)

然后通过将其放入单个Extension方法重新使用来完成:

[System.Runtime.CompilerServices.Extension]
public static IEnumerable<Text> GetValueOrDefault(this IEnumerable<Text> qry, int textId, string language)
{
    return qry.DefaultIfEmpty(qry.ByTextId(textId).ByLanguage(LanguageValues.English).Single()).ByTextId(textId).ByLanguage(language);
}
Run Code Online (Sandbox Code Playgroud)

你现在可以简单地打电话:

var text = MyDB.Texts.GetValueOrDefault(1, LanguageValues.Danish);
Run Code Online (Sandbox Code Playgroud)

请注意,这可以用作任何查询的最后一步,所以像这样的东西也可以工作:

var text = MyDB.Texts.Where(<some funky clause>).Where(<some other funky clause>).GetValueOrDefault(1,LanguageValues.Danish);
Run Code Online (Sandbox Code Playgroud)

正如人们所指出的那样,如果你使用多种备份语言,那么有一种方法比在原始问题中一次检查一种语言更好,但是这种过滤模式可以干净利落地工作,只需要为你定义正确的过滤器用例和策略.