LinqSelectでタプルを作成する


87

私はC#と.NET Framework 4.5.1を使用して、Entity Framework6.1.3を使用してSQLServerデータベースからデータを取得しています。

私はこれを持っています:

codes = codesRepo.SearchFor(predicate)
      .Select(c => new Tuple<string, byte>(c.Id, c.Flag))
      .ToList();

そして、それを実行すると、次のメッセージが表示されます。

LINQ to Entitiesでは、パラメーターのないコンストラクターと初期化子のみがサポートされています。

私が見つけたすべての例はほとんどこのようなものであるため、タプルをどのように作成する必要があるのか​​わかりません。

私はこれを試しました:

codes = codesRepo.SearchFor(predicate)
      .Select(c => Tuple.Create(c.Id, c.Flag))
      .ToList();

そして、このエラーが発生します:

LINQ to Entitiesは、メソッド 'System.Tuple`2 [System.String、System.Byte] Create [String、Byte](System.String、Byte)'メソッドを認識せず、このメソッドをストア式に変換できません。

問題はどこだ?


強く型付けされたオブジェクトを作成する必要があるようです。しかし、はい、良い質問です。賛成。
フレンチブルドッグ2015年

回答:


118

一方でその答えによってoctavioccl作品、それがより良い最初のプロジェクトへの匿名型にクエリ結果だし、次に列挙し、タプルに変換するために切り替えます。このようにして、クエリは必要なフィールドのみをデータベースから取得します。

codes = codesRepo.SearchFor(predicate)
    .Select(c => new { c.Id, c.Flag })
    .AsEnumerable()
    .Select(c => new Tuple<string, byte>(c.Id, c.Flag))
    .ToList();

注:上記のルールはEF6に適用されます。EF Coreは、タプルコンストラクターを介して(プロジェクションまたは結合/グループキーとして)タプルを自然にサポートします。たとえば、元のクエリは単純に機能します。

codes = codesRepo.SearchFor(predicate)
  .Select(c => new Tuple<string, byte>(c.Id, c.Flag))
  .ToList();

ただし、Tuple.Createメソッド(EF Core 2.x)ではありません。


非常に良い解決策-ありがとう!...このソリューションを別のnull許容値で拡張する必要がある場合はどうなりますか?.Select(c => new { c.Id, c.Flag, c.Foo?.Code })動作しません。
skyfrog 2017年

2
@skyfrog演算子?.は式ツリーではサポートされていません。ただし、それ以外に、匿名型を必要な数の値で拡張できます。必要に応じて名前を付けることを忘れないでください:)例c => new { c.Id, c.Flag, Code = (int?)c.Foo.Code }
Ivan Stoev 2017年

1
すごい!@Ivanに返信してくれてありがとう。とても近かった!...しかし、振り返ってみるといつでも簡単に言うことができます;-)
skyfrog 2017年

グレート答えは、EF-エンティティで使用することができます。..例えばdbCtx.MyEntity.Where()を選択し(..アノンオブジェクトへ...)など...。
joedotnot

44

C#7の回答を更新しただけで、より単純な構文を使用してValueTuplesを作成できるようになりました。

codes = codesRepo.SearchFor(predicate)
.Select(c => new { c.Id, c.Flag })
.AsEnumerable()
.Select(c => (c.Id, c.Flag))
.ToList();

タプルのプロパティに名前を付けることもできます。

codes = codesRepo.SearchFor(predicate)
.Select(c => new { c.Id, c.Flag }) // anonymous type
.AsEnumerable()
.Select(c => (Id: c.Id, Flag: c.Flag)) // ValueTuple
.ToList();

したがって、Item1またはItem2として使用する代わりに、IdまたはFlagとしてアクセスできます。

匿名とタプルの間の選択に関するその他のドキュメント


11

これを試して:

codes = codesRepo.SearchFor(predicate)
  .Select(c => Tuple.Create(c.Id, c.Flag))
  .ToList();

これはLINQでエンティティに受け入れられないことが通知されました。

別のオプションは、選択する前に結果をメモリにプルすることです。これを行う場合は、.AsEnumerable()の前にすべてのフィルタリングを実行することをお勧めします。これは、テーブル全体をプルバックしてからフィルタリングするのではなく、必要な結果のみをプルバックすることを意味します。

codes = codesRepo.SearchFor(predicate).AsEnumerable()
  .Select(c => Tuple.Create(c.Id, c.Flag))
  .ToList();

また、タプルタイプでコードをもう少し明示的にしたい場合は、Tuple.Create(c.Id、c.Flag)を新しいTuple(c.Id、c.Flag)に変更できます。


申し訳ありませんが、動作しません。質問をより詳細に更新しました。
vansFannel 2015年

11

ではエンティティへのLINQあなたは匿名型にするか、使用することができ発行DTO.Toの回避に投影することができますAsEnumerable拡張メソッドを:

codes = codesRepo.SearchFor(predicate).AsEnumerable().
      .Select(c => new Tuple<string, byte>(c.Id, c.Flag))
      .ToList();

この方法は、あなたがで作業することができますObjectにLINQの代わりにエンティティへのLINQをそれを呼び出す、あなたは何であなたを、あなたのクエリの結果を予測することができますので、後の使用のneed.The利点、AsEnumerable代わりにToListそれがあるAsEnumerableクエリを実行しない、それは遅延実行を保持します。これらのメソッドのいずれかを呼び出す前に、必ず最初にデータをフィルタリングすることをお勧めします。


5

私は答えを見つけました:

codes = codesRepo.SearchFor(predicate)
      .ToList()
      .Select(c => Tuple.Create(c.Id, c.Flag))
      .ToList();

いいえ、これによりSELECT *が生成されます
Mihai Bratulescu

1

この方法を使用してこれを行い、非同期を使用します。

var codes = await codesRepo.SearchFor(predicate)
                    .Select(s => new
                    {
                        Id = s.Id,
                        Flag = s.Flag
                    }).FirstOrDefaultAsync();

                var return_Value = new Tuple<string, byte>(codes.Id, codes.Flag);

0

ちょうど私の2セント:これはタイプ名で私を数回捕まえました:

いくつかのうなずく例:

    private Tuple<string, byte> v1()
    {
        return new Tuple<string, byte>("", 1);
    }

    private (string, int) v2()
    {
        return ("", 1);
    }

    private (string Id, byte Flag) v3()
    {
        return ("", 1);
    }

よろしく。


投稿した構文は機能しません。あなたがおそらく書くつもりだったのはですがpublic (string Id, byte Flag) SearchFor(Expression predicate)、これは重要なことではありません。2セントは答えではなく、コメントであるべきです。
M.Stramm

2
回答を更新しました-投稿する前に確認する必要がありました。同意しません; すべての情報は、このページがどのように配置されているかに関係なく、このページにアクセスするすべての訪問者に役立ちます。コメントは、回答のおかげで回答するだけでなく、意図も伝えません。
IbrarMumtaz

追加されたコンテンツは適切であり、コメントはコード例にうまく対応していないことに同意します。編集していただきありがとうございます。これがOPの質問に対する回答ではないことは明らかです(ただし、タプル関連の問題には役立つ可能性があります)。
M.Stramm
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.