【问题标题】:Check if value is null, and when it is, execute extra (sub)query检查值是否为空,如果为空,则执行额外的(子)查询
【发布时间】:2013-10-01 19:09:33
【问题描述】:

是否可以在 LINQ 查询中检查空值,当该值为空时,是否可以一次执行额外的(子)查询?

说明

我在我的数据库中声明了默认按钮,带有默认的描述。用户可以自定义这些按钮,这些设置存储在ButtonLocations 表中。现在,每个按钮都有一个标准的描述,用户可以编辑这个描述。当用户编辑描述时,它存储在我的数据库中的Descriptions 表中。 当我检索所有按钮时,我首先检查按钮是否具有特定描述(在 buttonlocations 中,带有左连接)。如果这不是真的(所以为空),我会检索默认描述。

目前,我获取所有实体及其描述,然后循环遍历所有实体以检查值是否为空。这会导致对数据库的多次查询。

var temp = (from bl in context.buttonLocations
                    join b in context.Buttons
                    on bl.ButtonID equals b.ButtonID into buttons
                    from button in buttons.DefaultIfEmpty()
                    join d in context.Descriptions
                    on new
                    {
                        ID = bl.ButtonLocationID,
                        langID = languageID,
                        originID = descriptionOriginID
                    }
                    equals new
                    {
                        ID = d.ValueID,
                        langID = d.LanguageID,
                        originID = d.DescriptionOriginID
                    }
                    into other
                    where bl.ButtonGroupID == buttonGroupId
                    from x in other.DefaultIfEmpty()
                    select new
                    {
                        Button = button,
                        ButtonLocation = bl,
                        Description = x
                    }).ToList();

        // Retrieve default descriptions if no specific one is set
        foreach (var item in temp)
        {
            if (item.Description == null)
            {
                item.Description = context.Descriptions
                    .FirstOrDefault(x => x.ValueID == item.Button.ButtonID && x.LanguageID == languageID && x.DescriptionOriginID == (short)DescriptionOriginEnum.Button);
            }
        }

【问题讨论】:

    标签: c# linq entity-framework


    【解决方案1】:

    我认为 Colin 使用 coalesce 运算符的答案应该可行,但如果无法做到,您可以尝试做一个子选择来获取这两个选项,然后按自定义源的偏好排序,并获得最高记录。 (我在这里假设任何给定的按钮实际上只有一个描述,并且多个描述不应该导致多个按钮。)

    var temp = (from bl in context.buttonLocations
            join b in context.Buttons
            on bl.ButtonID equals b.ButtonID into buttons
            from button in buttons.DefaultIfEmpty()
            let description = (
                    from d in context.Descriptions
                    where
                        d.LanguageID == languageID
                     && (
                          (
                            d.ValueID == bl.ButtonLocationID
                            && d.DescriptionOriginID == descriptionOriginID
                          )
                        ||
                          (
                            d.ValueID == b.ButtonID 
                            d.DescriptionOriginID == (short)DescriptionOriginEnum.Button
                          )
                        )
                    // this line puts custom descriptions first
                    orderby d.DescriptionOriginID == (short)DescriptionOriginEnum.Button
                            ? 1
                            : 0
                    select d
                    )
                    // this will get a custom description if there was one, otherwise
                    // the first one will be the default description
                    .FirstOrDefault() 
            where bl.ButtonGroupID == buttonGroupId
            select new
            {
              Button = button,
              ButtonLocation = bl,
              Description = description
            })
            .ToList();
    

    这显然有点尴尬,而且可能不是最有效的查询。我会先尝试将 coalesce 运算符移动到 let description = d ?? /*subselect*/ 行。

    【讨论】:

      【解决方案2】:

      null coalescing operator 应该在这里为您工作。像这样的:

      .....
      select new
      {
         Button = button,
         ButtonLocation = bl,
         Description ?? context.Descriptions
                               .FirstOrDefault(
                               x => x.ValueID == button.ButtonID 
                               && x.LanguageID == languageID 
                               && x.DescriptionOriginID == (short)DescriptionOriginEnum.Button)
      })
      

      【讨论】:

      • 我已经试过了,它没有用。它给出以下错误:'无法创建类型为“描述”的空常量值。此上下文仅支持实体类型、枚举类型或原始类型。'
      • 我认为您的错误来自实体框架,因为它无法将您的代码转换为 sql。 (short)DescriptionOriginEnum.Button 可能是罪魁祸首 - 在构造查询之前尝试将其分配给 short 变量。这可能会有所帮助:stackoverflow.com/a/17847159/150342
      • 两种提议的解决方案都无济于事。我想这是不可能的?
      • 我确信这是可能的,只是我认为 linq 不够好,无法提供太多帮助。我认为这值得一读 blogs.teamb.com/craigstuntz/2010/01/13/38525 并像 @SteveRuble 所显示的那样引入变量也有帮助
      猜你喜欢
      • 1970-01-01
      • 2014-02-11
      • 2019-07-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多