2010-07-26 6 views
12

Ich benutze Asp.net MVC mit Sharp Architecture.Linq Orderby random ThreadSafe für den Einsatz in ASP.NET

Ich habe diesen Code:

return _repositoryKeyWord.FindAll(x => x.Category.Id == idCAtegory) 
       .Take(50).ToList(); 

Wie kann ich durch gelegentliches bestellen? Hinweis: Ich möchte nicht die 50 extrahierten Artikel bestellen, ich möchte vorher bestellen und dann 50 Artikel extrahieren.

thks

+0

Wollen Sie sagen, dass Sie die gesamte Liste randomisiert möchten und dann die ersten 50 Elemente abrufen möchten? –

+0

Diese Frage dupliziert die verknüpfte Frage nicht. Diese Frage weist speziell auf ASP.NET hin, für das ein ThreadSafe-Direktzugriff erforderlich ist. Die verknüpfte Frage erwähnt ThreadSafe nicht –

Antwort

32

Eine Möglichkeit, effizient zu erreichen, ist eine Spalte, um Ihre Daten Shuffle hinzuzufügen, die mit einem zufälligen int aufgefüllt wird (wie jeder Datensatz erstellt wird).

Die Abfrage der Tabelle dann für den Zugriff wird ...

Random random = new Random(); 
int seed = random.Next(); 
result = result.OrderBy(s => (~(s.Shuffle & seed)) & (s.Shuffle | seed)); //^seed); 

Dies macht eine XOR-Operation in der Datenbank und Aufträge durch die Ergebnisse dieser XOR.

Vorteile: -

  1. Effizient: SQL nimmt die Ordnung, keine Notwendigkeit, die ganze Tabelle
  2. wiederholbar zu holen: (gut für Prüfung) - kann das gleiche Zufall Saatgut verwenden zu erzeugen die gleiche Zufalls Reihenfolge
  3. funktioniert auf den meisten (alle?) Entity Framework unterstützt Datenbanken

Dieser Ansatz wird von meinem Heimautomatisierungssystem verwendet, um Wiedergabelisten nach dem Zufallsprinzip zu sortieren. Es wählt jeden Tag ein neues Seed aus, das eine beständige Reihenfolge während des Tages gibt (was einfache Pause-/Wiederaufnahmekapazitäten erlaubt), aber jeden Tag einen neuen Blick auf jede Playlist.

+5

Diese Lösung machte mich ooooo und ahhhh gehen. – jfar

+1

jfar: Ich auch; Das ist pwesome. Obwohl ich nur das PK (welches ein int ist) statt eines Shuffle-Feldes benutzt und es funktioniert gut. Danke Hightechrider! –

+1

Das ist einfach unglaublich! Ich habe auch PK benutzt. Leistung ist hervorragend –

1
Random random = new Random(); 
return _repositoryKeyWord.FindAll(x => x.Category.Id == idCAtegory) 
       .OrderBy(x => r.Next()) 
       .Take(50).ToList(); 
+0

Hah, ich mag das. Wenn es jedoch schnelle Sortierung verwendet, könnte das zum Absturz bringen. Ich weiß, dass der Versuch, Array.Sort für einen inkonsistenten Parameter zu verwenden, eine Ausnahme verursacht. –

+0

Ich möchte den sql sehen, der erzeugt. Gibt es den ganzen Tisch zurück, sortiert und wirft alles außer den 50 besten Platten weg? –

+0

Ah, ja, das sollte sein. Nimm (50) .OrderBy (x => r.Next()), nicht umgekehrt. Edit: Macht nichts, ich habe die Frage falsch gelesen. –

1

Wahrscheinlich am besten Ihre eigene Erweiterungsmethode zu schreiben, es zu tun.

public static class Extensions 
{ 
    static readonly Random random = new Random(); 

    public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> items) 
    { 
     return Shuffle(items, random); 
    } 

    public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> items, Random random) 
    { 
     // Un-optimized algorithm taken from 
     // http://en.wikipedia.org/wiki/Knuth_shuffle#The_modern_algorithm 
     List<T> list = new List<T>(items); 
     for (int i = list.Count - 1; i >= 1; i--) 
     { 
      int j = random.Next(0, i); 
      T temp = list[i]; 
      list[i] = list[j]; 
      list[j] = temp; 
     } 
     return list; 
    } 
} 
+0

Random.Next ist nicht threadsicher, daher können Sie hier keine statische Variable verwenden, um den gemeinsamen Random-Wert zu speichern. –

+0

Und sicherlich, es muss i--, nicht i ++ –

+0

-1 für nicht threadsicher sein und Fehler in ASP.NET –

2

Sie können dies in T-SQL als here beschrieben. Ich denke nicht, dass du es in linq machen kannst, ohne das ganze Ergebnis in den Speicher zu laden und dann das meiste davon wegzuwerfen, was du nicht tun willst.

-2

Wie wäre es damit?

return _repositoryKeyWord.FindAll(x => x.Category.Id == idCAtegory) 
    .OrderBy (x => Guid.NewGuid()) 
    .Take(50).ToList(); 
+1

Dies funktioniert nicht. – nfplee

+0

Dies würde nicht funktionieren, weil Guid.NewGuid() in SQL übersetzt wird und das wird fehlschlagen. –