web-dev-qa-db-ja.com

Linq Selectでタプルを作成する

C#と.NET Framework 4.5.1を使用して、Entity Framework 6.1.3でSQL Serverデータベースからデータを取得しています。

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

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)'メソッドを認識せず、このメソッドをストア式に変換できません。

問題はどこにありますか?

70
VansFannel

answer by octavioccl は機能しますが、最初にクエリ結果を匿名型に投影してから、列挙可能に切り替えてTupleに変換する方が良いでしょう。これにより、クエリはデータベースから必要なフィールドのみを取得します。

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)。

81
Ivan Stoev

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 })
.AsEnumerable()
.Select(c => (Id: c.Id, Flag: c.Flag))
.ToList();

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

25
Rafael Merlin

これを試して:

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

これは、LINQ to entitiesで受け入れられないと通知されました。

別のオプションは、選択する前に結果をメモリにプルすることです。これを行う場合は、.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)に変更することもできます。

10
Dhunt

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

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

これを行うにはこのメソッドを使用し、非同期を使用します。

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);
1
MohammadSoori

ちょうど私の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);
    }

よろしく。

0
IbrarMumtaz