2016-01-08 5 views
10

Ich habe eine IQueryable Liste mit COLOURS KlassentypLambda-Ausdrücke bestellen durch und nehmen Ausgabe

IQueryable<COLOURS> renkler = dbcontext.colours.Select(s=>new COLOURS{ .... 

ich zufällig 2 Reihen zu bekommen, bin ich diesen Codeblock verwenden, dies zu tun:

renkler.OrderBy(o => Guid.NewGuid()).Take(2); 

ich möchte zwei Reihen, aber manchmal ist es immer 3 Zeilen oder 5 Zeilen:

enter image description here

Take(2) funktioniert nicht - was ist das Problem?

Ich habe etwas bemerkt, wenn ich

var result = NewProducts().OrderBy(o => Guid.NewGuid()).Take(2); 
int result_count = result.Count(); //This value is 2 :D 
            //but ToList() result 5 :D 

gesamte Methode überprüfen:

public IQueryable<COLOURS> NewProducts() 
{ 
    DateTime simdi = DateTime.Now; 
    DateTime simdi_30 = DateTime.Now.AddDays(-30); 

    var collection_products = DefaultColours() 
          .Where(w => ((w.add_date.Value >= simdi_30 && w.add_date.Value <= simdi) || w.is_new == true)) 
          .OrderByDescending(o => o.add_date).Take(200) 
          .Select(s => new COLOURS 
          { 
           colour_code = s.colour_code, 
           model_code = s.products.model_code, 
           sell_price = (decimal)s.sell_price, 
           market_price = (decimal)s.market_price, 
           is_new = (bool)s.is_new, 
           product_id = (int)s.product_id, 
           colour_name = s.name, 
           product_name = s.products.name, 
           description = s.products.description, 
           img_path = s.product_images.FirstOrDefault(f => f.is_main == true).img_path, 
           category_id = (int)s.category_relations.FirstOrDefault().category_id, 
           display_order = (short)s.display_order, 
           section_id = (int)s.products.section_id, 
           stock_amount = s.pr_sizes.Where(w => w.is_active == true && w.quantity >= 0).Count() > 0 ? (int)s.pr_sizes.Where(w => w.is_active == true && w.quantity >= 0).Sum(s2 => s2.quantity) : 0, 
                     section_name = s.products.pr_sections.name, 

          });  
    return collection_products; 
} 

public IQueryable<COLOURS> RandomNewProducts(int n) 
{ 
    var result = NewProducts().OrderBy(o => Guid.NewGuid()).Take(n); 
    int result_count = result.Count(); //2 
    //When I run this method it's getting 5 rows    
    return result; 
} 
+0

Nun, das kann die endgültige Abfrage beeinflussen oder nicht. Können Sie auch die Abfrage anzeigen, die angezeigt wird, wenn Sie "result" anzeigen? Ich würde etwas wie SELECT TOP 2 * FROM (SELECT TOP 200 * FROM ...) erwarten. – CodeCaster

+7

@theEmge: Viele Leute versuchen dir hier zu helfen, und sie alle sagen "Zeig mir den Code". Sie wollen den Code, damit sie Ihre Symptome reproduzieren können, um herauszufinden, was falsch läuft. Bitte hör auf, einige Code-Schnipsel in die Kommentare zu schreiben - setze den gesamten Code in die Frage, sonst verschwendest du nur die Zeit aller. Wenn Sie den Code auf etwas einfacheres reduzieren können, das immer noch das Problem aufweist, umso besser. –

+2

Das sieht wie die Take() - Erweiterungsmethode auf System.Linq.Enumerable aus, aber ist es wirklich? Könnte es eine andere Methode mit demselben Namen in einer anderen Klasse sein? Bitte posten Sie Ihren gesamten Code, einschließlich Referenzen/'using'-Anweisungen und die DefaultColours() -Methode. –

Antwort

2

Diese Sie keine Lösung sein kann, aber es ist schwer, Kommentare mit mehrzeiligen Code und Bildern zu formatieren.

Ich bin mir ziemlich sicher, dass dies ein Problem mit Ihrem Datenanbieter ist. Vielleicht implementiert diese Komponente Take() nicht so, wie es sollte.

Ich habe versucht, Ihre Konstellation für den Wiederaufbau, sondern von jedem IQueryable Anbieter Ich baute auf eine List<> mit 500 Objekten und nannte AsQueryable() die Methodensignatur zu erfüllen.

public static IQueryable<COLOURS> DefaultColours() 
    { 
     const int COUNT = 500; 

     List<COLOURS> x = new List<COLOURS>(); 

     var startDate = DateTime.Today.AddDays(-1 * (int)(COUNT/2)); 

     // add 500 date values, and use the date and any random bool value 
     for (int i = 0; i < COUNT; i++) 
      x.Add(new COLOURS() { add_date = startDate.AddDays(i), is_new = i % 3 == 0 }); 

     return x.AsQueryable(); 
    } 

Aber wenn ich das tue, die Take() Methode immer zurückkehrt zwei (unterschiedliche) Artikel jedes Mal - so wie jemand erwarten würde:

debugger view

0

Dies aufgrund der o könnte = > Guid.NewGuid() Lambda.

Der Sortieralgorithmus erfordert einen eindeutigen Schlüssel, der an jedes Element gebunden ist. Das Aufrufen von Guid.NewGuid() bedeutet, dass jedem gegebenen Element mehrere Schlüssel zugeordnet sein können, abhängig davon, wann es aufgerufen wird. Linq versucht opportunistisch zu sein, wie es auf Sätzen funktioniert, so dass dies z. die beiden niedrigsten Elemente sind plötzlich nicht mehr die zwei niedrigsten Elemente während des Sortiervorgangs.

Sie sollten versuchen, eine Liste zufälliger Ganzzahlen zu sortieren, wobei sich diese Ganzzahlen zufällig ändern, wenn der Sortieralgorithmus versucht, sie abzurufen. Dies funktioniert nur, wenn der Sortieralgorithmus garantiert, dass die Schlüsselfunktion für jedes Element einmal aufgerufen wird.

Die Dokumentation auf der OrderBy sagt nicht, ob der Sortieralgorithmus die Schlüsselfunktion mehr als einmal für jedes Element aufrufen darf, daher ist es am besten, den schlimmsten Fall anzunehmen, es sei denn, Sie können das Gegenteil beweisen.

Als (hoffentlich) einfache Möglichkeit, dies zu testen, wenn Sie den zufälligen Schlüssel vorübergehend als permanentes Element Ihres COLOR-Objekts einschließen können, damit sich die Reihenfolge während der Sortierung nicht ändert, sollte die .Take() genau funktionieren wie beabsichtigt.

Auch Guid.NewGuid() ist nicht schnell genug. Wenn Sie also diesen temporären Test in eine permanente Lösung umwandeln, die für jedes Objekt ein wenig mehr Speicher benötigt, kann sich die Geschwindigkeit Ihres Codes ebenfalls verbessern.

Verwandte Themen