Linq Select'te Tuple Oluşturun


89

Entity Framework 6.1.3 ile bir SQL Server veritabanından veri alırken C # ve .NET Framework 4.5.1 ile çalışıyorum.

Bu bende var:

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

Ve çalıştırdığımda şu mesajı alıyorum:

LINQ to Entities'de yalnızca parametresiz oluşturucular ve başlatıcılar desteklenir.

Tuple'ı nasıl yaratmam gerektiğini bilmiyorum çünkü bulduğum tüm örnekler çoğunlukla bunun gibi.

Bunu denedim:

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

Ve şu hatayı alın:

LINQ to Entities, 'System.Tuple`2 [System.String, System.Byte] Create [String, Byte] (System.String, Byte)' yöntemini tanımıyor ve bu yöntem bir mağaza ifadesine çevrilemez.

Sorun nerede?


Kesinlikle yazılmış bir nesne oluşturmanız gerekecek gibi görünüyor. Ama evet, güzel soru; oy verildi.
frenchie

Yanıtlar:


121

Octavioccl tarafından verilen yanıt işe yarasa da , önce sorgu sonucunu anonim türe yansıtmak ve ardından numaralandırılabilir duruma geçmek ve onu tuple'a dönüştürmek daha iyidir. Bu şekilde sorgunuz veri tabanından yalnızca gerekli alanları alacaktır.

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

Not: Yukarıdaki kural EF6 için geçerlidir. EF Core doğal olarak tuple'ları (projeksiyonda veya birleştirme / grup anahtarları olarak) tuple yapıcısı aracılığıyla destekler, örneğin orijinal sorgu basitçe çalışır

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

ancak Tuple.Createyöntem değil (EF Core 2.x).


Çok iyi çözüm - Teşekkürler! ... Bu çözümü başka bir boş değerle genişletmek zorunda kalsaydım ne olacak? .Select(c => new { c.Id, c.Flag, c.Foo?.Code })çalışmıyor.
skyfrog

2
@skyfrog Operatör ?., ifade ağaçlarında desteklenmez. Ancak bunun dışında, anonim türü istediğiniz kadar değerle genişletebilirsiniz - sadece gerektiğinde onlara ad vermeyi unutmayın :) örneğinc => new { c.Id, c.Flag, Code = (int?)c.Foo.Code }
Ivan Stoev

1
Harika! Cevabınız için @ Ivan çok teşekkürler. Çok yakındım! ... ama geriye bakarken söylemek her zaman kolaydır ;-)
skyfrog

Harika cevap, EF-Varlıkları ile kullanılabilir .. örn. DbCtx.MyEntity.Where (). Seç (.. bir nesneye ...). Vb ...
31'e katılmadı

50

C # 7 için sadece güncellenmiş bir cevap, artık ValueTuples oluşturmak için daha basit bir sözdizimi kullanabilirsiniz.

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

Hatta şimdi demetin özelliklerini adlandırabilirsiniz:

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

Dolayısıyla, onu Öğe1 veya Öğe2 olarak kullanmak yerine, ona Kimlik veya Bayrak olarak erişebilirsiniz.

Anonim ve isimsiz grup arasında seçim yapma hakkında daha fazla belge


11

Bunu dene:

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

Bunun varlıklara LINQ'da kabul edilmediği konusunda bilgilendirildim.

Diğer bir seçenek de sonucu seçmeden önce hafızaya almak olacaktır. Bunu yapacaksanız, filtrelemenin tamamını .AsEnumerable () 'dan önce yapmanızı tavsiye ederim çünkü bu, tüm tabloyu geri çekip filtrelemek yerine yalnızca istediğiniz sonuçları geri çekiyorsunuz demektir.

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

ayrıca Tuple.Create (c.Id, c.Flag), kodu tuples türlerinde biraz daha açık hale getirmek istiyorsanız yeni Tuple (c.Id, c.Flag) olarak değiştirilebilir.


Üzgünüm işe yaramıyor. Sorumu daha fazla ayrıntıyla güncelledim.
VansFannel

10

Gelen kuruluşlara linq anonim bir türü üzerine veya kullanabilirsiniz sorunu bir DTO.To kaçınmak üzerine yansıtabilirsiniz AsEnumerableuzatma yöntemi:

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

Bu yöntem , Linq to Entities yerine Linq to Object ile çalışmanıza izin verir , böylece onu çağırdıktan sonra, sorgunuzun sonucunu ihtiyacınız olan her şeye yansıtabilirsiniz. Bunun yerine kullanmanın avantajı, sorguyu yürütmemesi , ertelenmiş yürütmeyi muhafaza etmesidir. Bu yöntemlerden birini çağırmadan önce her zaman verilerinizi filtrelemek iyi bir fikirdir.AsEnumerableToListAsEnumerable


-1 Bu, OP tarafından istenen şeyin aynısını yapmaz. Bazen, Birleştirme amaçları için bir sorguda Tuple oluşturabilmek önemlidir.
Aron

5

Cevabı buldum:

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

Hayır, bu SELECT * oluşturacak
Mihai Bratulescu

1

Bunu yapmak ve zaman uyumsuz kullanmak için bu yöntemi kullanın.

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

Sadece iki sentim: bu beni birkaç kez tip isimleriyle yakaladı:

Birkaç ahlaksız örnek:

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

Saygılarımızla.


Gönderdiğiniz sözdizimi çalışmıyor. Muhtemelen yazmak istediğin şey public (string Id, byte Flag) SearchFor(Expression predicate), ama bu konunun dışında. İki sent bir cevap değil, yorum olmalıdır.
M.Stramm

2
Cevabımı güncelledim - göndermeden önce kontrol etmeliydim. Katılmıyorum; tüm bilgiler, nasıl konumlandırıldığına bakılmaksızın bu sayfaya gelen tüm ziyaretçiler için yararlıdır. Yorumlar, cevaplar sayesinde hem niyet hem de cevap vermez.
IbrarMumtaz

Eklenen içeriğin iyi olduğunu ve yorumların kod örneklerine pek uygun olmadığını kabul ediyorum. Düzenlediğiniz için teşekkürler, şimdi bunun OP'nin sorusuna bir cevap olmadığı açıktır (ancak tuple ile ilgili sorunlarda yardımcı olabilir).
M.Stramm
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.