0

次のクラスを持つEntityFrameworkモデルがあります(見やすくするためにクラスを簡略化しました)。

 PuzzleItem
 -PuzzleId (int, primary key)
 -Title

 PuzzleProgress
 -ProgressId (int, primary key)
 -PuzzleId (FK)
 -UserId (FK)

私にはいくつPuzzleItemかのレベルがあります。ユーザーが前のレベルを完了したときにそのPuzzleProgressレベルのレコードを挿入することにより、ユーザーがどのレベルにいるかを追跡します。まず、新しいユーザーはで1つのエントリをPuzzleProgress持ちPuzzleId = 1ます。

私のコードでは、次のステートメントを使用して左外側結合を実行しているので、すべてのパズルのリストを取得し、どのパズルが解決されていないかを示します。StackOverflowからこの投稿を参照しました。

これが私のコードです:

var result = from pzs in e.PuzzleItems
                         join prg in e.PuzzleProgresses on pzs equals prg.PuzzleItem
                         into pzs_prg_tbl
                         from pzs_prg in pzs_prg_tbl.DefaultIfEmpty()
                         where pzs_prg.UserId == userId
                         select new SimplePuzzleItem()
                         {
                             PuzzleId = pzs_prg.PuzzleId,
                             PuzzleName = pzs_prg.PuzzleItem.Title,
                             IsUnlocked = (pzs_prg == null?false:true)
                         };

コードを実行した後、この新しいユーザーの最初のレベルのみが返されます(PuzzleItemテーブルには3つのレコードがあります)。

コードを試してみましたが、上に貼り付けたコードが最も近いコードです。誰かが私を正しい方向に向けることができますか?ありがとう!

4

2 に答える 2

4

コードをもっと見ずに正確に言うのは少し難しいですが、where pzs_prg.UserId == userIdおそらく左外側の結合を否定しています。

つまり、意図している場合PuzzleItems LEFT JOIN PuzzleProgressは、PuzzleProgressがない場合でもすべてのPuzzleItemが必要です。ただし、where pzs_prg.UserId == userIdPuzzleProgressは(値userIdの)UserIdを持っている必要があるため、nullにすることはできません。したがって、効果的に内部結合があります。

個人的には、linqで結合(左または内部)を行う「正しい」方法が好きではないので、これがlinqステートメントを修正する方法です。

        var result = from pz in db.PuzzleItems
                     from pg in db.PuzzleProgresses
                                  .Where(pg => pg.PuzzleId == pz.PuzzleId)
                                  .Where(pg => pg.UserId == userId)
                                  .DefaultIfEmpty()
                     select new
                                {
                                    PuzzleId = pz.PuzzleId,
                                    PuzzleName = pz.Title,
                                    IsUnlocked = (pg != null)
                                };

これは、私がずっと前に学んだSQL結合によく似ているので、私の考えに合っています。

結合タイプの構文をリファクタリングする場合は、この「複数の条件を使用したc#でのLINQ結合」を参照してください。

于 2013-03-25T17:47:57.953 に答える
1

where句はレコードを除外していると思います。左結合にwhere句を含める必要があります。そのようです:

var result = from pzs in e.PuzzleItems
             join prg in e.PuzzleProgresses on new { pzs.PuzzleId, UserId = userId } equals new { prg.PuzzleId, prg.UserId }
             into pzs_prg_tbl
             from pzs_prg in pzs_prg_tbl.DefaultIfEmpty()
             select new SimplePuzzleItem()
             {
               PuzzleId = pzs_prg.PuzzleId,
               PuzzleName = pzs_prg.PuzzleItem.Title,
               IsUnlocked = (pzs_prg == null?false:true)
             };
于 2013-03-25T17:37:46.947 に答える