Siparişin artan ve null değerlerin son olması gereken boş sütuna göre LINQ sırası


141

Bir ürün listesini fiyatlarına göre sıralamaya çalışıyorum.

Sonuç kümesinin, ürünleri sütuna göre düşükten yükseğe doğru fiyatlandırması gerekir LowestPrice. Ancak, bu sütun geçersizdir.

Listeyi aşağıdaki gibi azalan sırada sıralayabilirsiniz:

var products = from p in _context.Products
   where p.ProductTypeId == 1
   orderby p.LowestPrice.HasValue descending
   orderby p.LowestPrice descending
   select p;

// returns:    102, 101, 100, null, null

Ancak bunu artan düzende nasıl sıralayacağımı anlayamıyorum.

// i'd like: 100, 101, 102, null, null

11
orderby p.LowestPrice ?? Int.MaxValue;basit bir yol.
PostMan

3
@PostMan: Evet, basit, doğru sonucu elde ediyor, ancak OrderByDescending, ThenBydaha net.
jason

@ Jason, evet ben için sözdizimini bilmiyordum orderbyve onu arıyor yan iz var :)
PostMan

Yanıtlar:


161

Her iki sütunu da aynı sırada koymayı deneyin.

orderby p.LowestPrice.HasValue descending, p.LowestPrice

Aksi takdirde, her sipariş toplama üzerinde her seferinde yeniden sipariş veren ayrı bir işlemdir.

Bu, önce değeri olanları, daha sonra değerin sırasını "sonra" sıralamalıdır.


22
Yaygın hata, insanlar Lamda Syntax ile aynı şeyi yapar. .OrderBy'yi .ThenBy yerine iki kez kullanarak.
DaveShaw

1
Bu değer üstünde alanlar ve altta null alanlar ile sipariş için çalıştı ben bunu kullandım: orderby p.LowestPrice == null, p.LowestPrice ascending Umut birine yardımcı olur.
shaijut

@DaveShaw bahşiş için teşekkür ederim - özellikle yorum bir - çok düzenli - love it
Demetris Leptos

86

Gerçekten LINQ sorgu sözdizimini ve LINQ yöntem çağrılarına nasıl çevrildiğini anlamaya yardımcı olur.

Şekline dönüştü

var products = from p in _context.Products
               where p.ProductTypeId == 1
               orderby p.LowestPrice.HasValue descending
               orderby p.LowestPrice descending
               select p;

derleyici tarafından

var products = _context.Products
                       .Where(p => p.ProductTypeId == 1)
                       .OrderByDescending(p => p.LowestPrice.HasValue)
                       .OrderByDescending(p => p.LowestPrice)
                       .Select(p => p);

Bu kesinlikle istediğiniz şey değil. Tarafından bu sıralar Product.LowestPrice.HasValuehalinde descendingdüzen ve o sırada tüm koleksiyonu yeniden sıralar Product.LowestPricehalindedescending sırayla.

Ne istiyorsun

var products = _context.Products
                       .Where(p => p.ProductTypeId == 1)
                       .OrderByDescending(p => p.LowestPrice.HasValue)
                       .ThenBy(p => p.LowestPrice)
                       .Select(p => p);

hangi sözdizimini kullanarak elde edebilirsiniz

var products = from p in _context.Products
               where p.ProductTypeId == 1
               orderby p.LowestPrice.HasValue descending,
                       p.LowestPrice
               select p;

Sorgu sözdiziminden yöntem çağrılarına çevirilerin ayrıntıları için, dil belirtimine bakın. Ciddi anlamda. Oku onu.


4
+1 ya da sadece ... LINQ sorgu sözdizimini yazmayın :) Yine de iyi bir açıklama
sehe

18

Dize değerleri için çözüm gerçekten garip:

.OrderBy(f => f.SomeString == null).ThenBy(f => f.SomeString) 

Çalışmanın tek nedeni, ilk ifadenin OrderBy(), sıralama booldeğerlerinin: true/ olmasıdır false. falsesonuç önce truesonucu (nullables) takip eder ve ThenBy()null olmayan değerleri alfabetik olarak sıralar.

Yani, daha okunabilir bir şey yapmayı tercih ederim:

.OrderBy(f => f.SomeString ?? "z")

Eğer SomeStringnull, bu alacaktır "z"ve alfabetik sonra sıralama herşeyi.

NOT: Bu nihai bir çözüm değildir, çünkü "z"z değerlerinden önce gelir zebra.

UPDATE 9/6/2016 - @jornhd hakkında yorum, gerçekten iyi bir çözüm, ama yine de biraz karmaşık, bu yüzden böyle bir Extension sınıfına sarmanızı tavsiye ederim:

public static class MyExtensions
{
    public static IOrderedEnumerable<T> NullableOrderBy<T>(this IEnumerable<T> list, Func<T, string> keySelector)
    {
        return list.OrderBy(v => keySelector(v) != null ? 0 : 1).ThenBy(keySelector);
    }
}

Ve basit bir şekilde kullanın:

var sortedList = list.NullableOrderBy(f => f.SomeString);

2
Kötü sabit olmadan bu daha okunabilir olduğunu düşünüyorum: .OrderBy (f => f.SomeString! = Null? 0: 1) .ThenBy (f => f.SomeString)
jornhd

14

Bu durumda başka bir seçeneğim var. Listem objList ve sipariş vermeliyim ama sonunda boş olmalı. benim kararım:

var newList = objList.Where(m=>m.Column != null)
                     .OrderBy(m => m.Column)
                     .Concat(objList.where(m=>m.Column == null));

Bu, null yerine 0 gibi diğer değerlerle sonuçlanan senaryolarda çalışabilir.
Naresh Ravlani

Evet. Null değerini 0 yerine değiştirin.
Gurgen Hovsepyan

benim için işe yarayan tek cevap bu, geri kalanı null'ları listenin başında tuttu.
BMills

9

Bunun için bir LINQ çözümü bulmaya çalışıyordum, ancak buradaki yanıtlardan çözemedim.

Son cevabım şuydu:

.OrderByDescending(p => p.LowestPrice.HasValue).ThenBy(p => p.LowestPrice)

7

benim kararım:

Array = _context.Products.OrderByDescending(p => p.Val ?? float.MinValue)

7

Ben uzantısı yöntemleri kullanıyorum ve aynı zamanda benim öğe bir dize, bu nedenle hayır çünkü ben geldi budur .HasValue:

.OrderBy(f => f.SomeString == null).ThenBy(f => f.SomeString)

Bu, bellekteki LINQ 2 nesneleriyle çalışır. EF veya herhangi bir DB ORM ile test etmedim.


0

Bir keySelector öğesinin child özelliğine göre sıralamak istiyorsanız null olup olmadığını denetlemek için uzantı yöntemi aşağıdadır.

public static IOrderedEnumerable<T> NullableOrderBy<T>(this IEnumerable<T> list, Func<T, object> parentKeySelector, Func<T, object> childKeySelector)
{
    return list.OrderBy(v => parentKeySelector(v) != null ? 0 : 1).ThenBy(childKeySelector);
}

Ve basit bir şekilde kullanın:

var sortedList = list.NullableOrderBy(x => x.someObject, y => y.someObject?.someProperty);

0

İşte başka bir yol:

//Acsending
case "SUP_APPROVED_IND": qry =
                            qry.OrderBy(r => r.SUP_APPROVED_IND.Trim() == null).
                                    ThenBy(r => r.SUP_APPROVED_IND);

                            break;
//….
//Descending
case "SUP_APPROVED_IND": qry =
                            qry.OrderBy(r => r.SUP_APPROVED_IND.Trim() == null).
                                    ThenByDescending(r => r.SUP_APPROVED_IND); 

                            break;

SUP_APPROVED_IND is char(1) in Oracle db.

Şu r.SUP_APPROVED_IND.Trim() == nullşekilde ele alınır:trim(SUP_APPROVED_IND) is null Oracle db.

Ayrıntılar için buna bakın: Varlık çerçevesinde null değerleri nasıl sorgulayabilirim?


0

Başka Bir Seçenek (senaryomuz için kullanışlıydı):

Bir Kullanıcı Masamız var. ADName, LastName, FirstName

  • Kullanıcılar alfabetik olmalıdır
  • Ad / Soyadına sahip olmayan ve ADName'lerine dayanan ancak Kullanıcı Listesinin sonunda bulunan hesaplar
  • "0" kimliğine sahip Sahte Kullanıcı ("Seçim Yok") Her zaman en üstte olmalıdır.

Tablo şemasını değiştirdik ve bazı sıralama gruplarını tanımlayan bir "SortIndex" Sütunu ekledik. (5 boşluk bıraktık, böylece daha sonra grup ekleyebiliriz)

ID | ADName |      First Name | LastName | SortIndex
0    No Selection  null         null     | 0
1    AD\jon        Jon          Doe      | 5
3    AD\Support    null         null     | 10     
4    AD\Accounting null         null     | 10
5    AD\ama        Amanda       Whatever | 5

Şimdi, sorgu-bilge olurdu:

SELECT * FROM User order by SortIndex, LastName, FirstName, AdName;

Yöntem İfadelerinde:

db.User.OrderBy(u => u.SortIndex).ThenBy(u => u.LastName).ThenBy(u => u.FirstName).ThenBy(u => u.AdName).ToList();

beklenen sonucu verir:

ID | ADName |      First Name | LastName | SortIndex
0    No Selection  null         null     | 0
5    AD\ama        Amanda       Whatever | 5
1    AD\jon        Jon          Doe      | 5
4    AD\Accounting null         null     | 10
3    AD\Support    null         null     | 10     
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.