1

LINQ クエリで null 値をチェックし、値が null の場合、余分な (サブ) クエリを一度に実行することはできますか?

説明

データベースで宣言されたデフォルトのボタンがあり、デフォルトの説明があります。ユーザーはこれらのボタンをカスタマイズでき、これらの設定はButtonLocationsテーブルに保存されます。現在、すべてのボタンには標準の説明があり、ユーザーはこの説明を編集できます。ユーザーが説明を編集するとDescriptions、データベースのテーブルに保存されます。すべてのボタンを取得するときは、最初にボタンに特定の説明があるかどうかを確認します ( buttonlocationsで左結合を使用)。これが当てはまらない (null の場合) 場合は、デフォルトの説明を取得します。

現在、すべてのエンティティとその説明を取得し、その後、それらすべてをループして値が null かどうかを確認します。これにより、データベースへの複数のクエリが発生します。

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);
            }
        }
4

2 に答える 2

0

合体演算子を使用したコリンの答えはうまくいくはずですが、それができない場合は、両方のオプションを取得するサブセレクトを試してから、カスタムソースの優先順位で並べ替え、トップレコードを取得してみてください。(ここでは、特定のボタンには実際には 1 つの説明しかなく、複数の説明が複数のボタンになるべきではないと仮定しています。)

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();

これは明らかに少しぎこちなく、おそらく最も効率的なクエリではありません。合体演算子をlet description = d ?? /*subselect*/最初に行に移動してみます。

于 2013-10-01T11:09:33.300 に答える
0

ここでは、 null 合体演算子が機能するはずです。このようなもの:

.....
select new
{
   Button = button,
   ButtonLocation = bl,
   Description ?? context.Descriptions
                         .FirstOrDefault(
                         x => x.ValueID == button.ButtonID 
                         && x.LanguageID == languageID 
                         && x.DescriptionOriginID == (short)DescriptionOriginEnum.Button)
})
于 2013-10-01T08:35:36.720 に答える