LINQとLambdaに参加する


458

LINQとLambdaで書かれたクエリに問題があります。これまでのところ、多くのエラーが発生しています。ここに私のコードがあります。

int id = 1;
var query = database.Posts.Join(database.Post_Metas,
                                post => database.Posts.Where(x => x.ID == id),
                                meta => database.Post_Metas.Where(x => x.Post_ID == id),
                                (post, meta) => new { Post = post, Meta = meta });

私はLINQを初めて使用するので、このクエリが正しいかどうかはわかりません。


11
あなたは何を成し遂げようとしているのですか?
ヘルマン・ロドリゲス

4
文でクエリに何をさせたいですか?
ハンター、

6
あなたのキーセレクタがされている方法は複雑すぎます。IDで選択する場合は、x => x.IDで十分です。
エリックリッペルト2010年

1
データベースから投稿とその投稿のメタデータを取得したかったのです。
デビッド

回答:


1057

SQL構文に精通している場合は、LINQクエリ構文を使用する方がはるかに明確で自然であり、エラーを見つけやすくなります。

var id = 1;
var query =
   from post in database.Posts
   join meta in database.Post_Metas on post.ID equals meta.Post_ID
   where post.ID == id
   select new { Post = post, Meta = meta };

しかし、ラムダの使用に本当にこだわっている場合、構文はかなりずれています。これは、LINQ拡張メソッドを使用した同じクエリです。

var id = 1;
var query = database.Posts    // your starting point - table in the "from" statement
   .Join(database.Post_Metas, // the source table of the inner join
      post => post.ID,        // Select the primary key (the first part of the "on" clause in an sql "join" statement)
      meta => meta.Post_ID,   // Select the foreign key (the second part of the "on" clause)
      (post, meta) => new { Post = post, Meta = meta }) // selection
   .Where(postAndMeta => postAndMeta.Post.ID == id);    // where statement

10
@Emanuele Greco、編集に関して、「IDフィールドの等価性はJOIN条件で設定されています。WHERE句を使用する必要はありません!」:WHERE句は、IDフィールド間の等価性をテストしていません。投稿ID間の等価性をテストしています。列とクエリの外部で宣言されたidパラメータ。
Daniel Schaffer 2013年

9
素晴らしく、 lambda使いやすく理解しやすい引用
Piotr Kula 2013

1
素晴らしい例
おもちゃ

1
ラムダの説明がラムダで書かれていることがあります。よく説明しました。
ピンチ

80

これで2つの方法が考えられます。使用する LINQPad:(あなたがしているLINQに新しい場合は非常に貴重なの)とダミーデータベース、私は次のクエリを構築しました

Posts.Join(
    Post_metas,
    post => post.Post_id,
    meta => meta.Post_id,
    (post, meta) => new { Post = post, Meta = meta }
)

または

from p in Posts
join pm in Post_metas on p.Post_id equals pm.Post_id
select new { Post = p, Meta = pm }

この特定のケースでは、LINQ構文はよりクリーンだと思います(どちらが最も読みやすいかに応じて、2つを切り替えます)。

ただし、データベースに適切な外部キーがある場合(postとpost_metaの間)、大量のレコードをロードする場合を除いて、明示的な結合はおそらく必要ないということを指摘しておきます。 。あなたの例は、あなたが単一の投稿をロードしようとしていることとそれがメタデータであることを示しているようです。各投稿に多くのpost_metaレコードがあると仮定すると、次のようにすることができます。

var post = Posts.Single(p => p.ID == 1);
var metas = post.Post_metas.ToList();

n + 1の問題を回避したい場合は、LINQ to SQLにすべての関連アイテムを一度にロードするように明示的に指示できます(ただし、これはL2Sに精通している場合の高度なトピックかもしれません)。以下の例では、「Postをロードするときに、「Post_metas」プロパティで表される外部キーを介して、Postに関連付けられているすべてのレコードもロードします」と述べています。

var dataLoadOptions = new DataLoadOptions();
dataLoadOptions.LoadWith<Post>(p => p.Post_metas);

var dataContext = new MyDataContext();
dataContext.LoadOptions = dataLoadOptions;

var post = Posts.Single(p => p.ID == 1); // Post_metas loaded automagically

同じタイプまたは多くの異なるタイプのLoadWith単一のセットに対して多くの呼び出しを行うことができDataLoadOptionsます。ただし、これをたくさん行う場合は、キャッシュを検討することをお勧めします。


1
LinqPad CRM 2016
Kiquenet 2016

49

ダニエルは構文の関係について適切に説明していますが、チームが理解しやすいように、このドキュメントをチームのためにまとめました。これが誰かを助けることを願っていますここに画像の説明を入力してください


ここにあるような値のリストを単に処理しているときは、これは機能しません。オブジェクトにidプロパティはありません。
Talspaugh27、2018年

これは本当に便利だと思いましたが、結合列を追加する必要があるエラーが発生しました。また、@ Mark Byersによって投稿された回答を見ると、結合列Post_IDには2番目のエイリアスのフィールドがありますmeta => meta.Post_ID。この図の例でg.idは、元の選択ステートメントの一部はJOIN gStatus g on g.id、最後のラムダ式で複製されていません。
SausageFingers

3
私はこれを、OPによって投稿された回答に必要な実際のlinqへの参照として投稿しようとしていませんでした。これは、SQLをLinq形式に移行する方法のリファレンスであり、私の入力は元の質問とは少し異なっていました。gStatus値のクラスを作成していた場合、idプロパティをその上に配置し、はい、g => g.idで結合します。コードをできるだけシンプルに保つために値のリストを使用しました。
Talspaugh27、2018年

@ Talspaugh27では、SQLクエリでg.idのgStatusに結合するのはなぜですか。それは間違いですか、それとも意図的なものですか?
ドラマー

SQLテーブルの@Drammyでは、各列に名前を付ける必要があります。これは、これらのIDを保持するために厳密に1列のテーブルだったため、idという名前の列を使用しただけで、List <int>にはその問題はありません。そのように設定して public class IdHolder{ int id } から、gStatusでそのオブジェクトを使用した場合 List<IdHolder> gStatus = new List<IdHolder>(); gStatus.add(new IdHolder(){id = 7}); gStatus.add(new IdHolder(){id = 8}); 、Linqが変更されて、t =>t.value.TaskStatusId, g=>g.id その変更は理にかなっていますか?
Talspaugh27、19年

37

キーセレクターが正しくありません。問題のテーブルのタイプのオブジェクトを取得し、結合で使用するキーを返す必要があります。私はあなたがこれを意味すると思います:

var query = database.Posts.Join(database.Post_Metas,
                                post => post.ID,
                                meta => meta.Post_ID,
                                (post, meta) => new { Post = post, Meta = meta });

キーセレクターの一部としてではなく、後でwhere句を適用できます。


9

私がLINQ + EntityFrameworkを開始したとき、私はこれらの例を1日間見つめていたので投稿しました。

EntityFrameworkを使用Metaしていて、Postモデルオブジェクトに名前が付けられたナビゲーションプロパティが設定されている場合、これは非常に簡単です。エンティティを使用していて、そのナビゲーションプロパティがない場合、何を待っていますか?

database
  .Posts
  .Where(post => post.ID == id)
  .Select(post => new { post, post.Meta });

最初にコードを実行している場合は、このようにプロパティを設定します。

class Post {
  [Key]
  public int ID {get; set}
  public int MetaID { get; set; }
  public virtual Meta Meta {get; set;}
}

5

私はこのようなことをしました。

var certificationClass = _db.INDIVIDUALLICENSEs
    .Join(_db.INDLICENSECLAsses,
        IL => IL.LICENSE_CLASS,
        ILC => ILC.NAME,
        (IL, ILC) => new { INDIVIDUALLICENSE = IL, INDLICENSECLAsse = ILC })
    .Where(o => 
        o.INDIVIDUALLICENSE.GLOBALENTITYID == "ABC" &&
        o.INDIVIDUALLICENSE.LICENSE_TYPE == "ABC")
    .Select(t => new
        {
            value = t.PSP_INDLICENSECLAsse.ID,
            name = t.PSP_INDIVIDUALLICENSE.LICENSE_CLASS,                
        })
    .OrderBy(x => x.name);

4

それは次のようなものかもしれません

var myvar = from a in context.MyEntity
            join b in context.MyEntity2 on a.key equals b.key
            select new { prop1 = a.prop1, prop2= b.prop1};

1

1は1つの2つの異なるテーブル結合に等しい

var query = from post in database.Posts
            join meta in database.Post_Metas on 1 equals 1
            where post.ID == id
            select new { Post = post, Meta = meta };

1

このlinqクエリはうまくいくはずです。投稿メタを持つすべての投稿を取得します。

var query = database.Posts.Join(database.Post_Metas,
                                post => post.postId, // Primary Key
                                meta => meat.postId, // Foreign Key
                                (post, meta) => new { Post = post, Meta = meta });

同等のSQLクエリ

Select * FROM Posts P
INNER JOIN Post_Metas pm ON pm.postId=p.postId

3番目の
パラメーターの

3
これは受け入れられた回答と同じで、7年後の-1
reggaeguitar
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.