36 votes

Linq to Entities, ordre aléatoire

Comment puis-je retourner des entités correspondantes dans un ordre aléatoire?
Pour que ce soit clair, il s’agit de trucs Entity Framework et LINQ to Entities.

(code aérien)

 IEnumerable<MyEntity> results = from en in context.MyEntity
                                where en.type == myTypeVar
                                orderby ?????
                                select en;
 

Merci

Modifier:
J'ai essayé d'ajouter ceci au contexte:

 public Guid Random()
{
    return new Guid();
}
 

Et en utilisant cette requête:

 IEnumerable<MyEntity> results = from en in context.MyEntity
                                where en.type == myTypeVar
                                orderby context.Random()
                                select en;
 

Mais j'ai eu cette erreur:

 System.NotSupportedException: LINQ to Entities does not recognize the method 'System.Guid Random()' method, and this method cannot be translated into a store expression..
 

Modifier (code actuel):

 IEnumerable<MyEntity> results = (from en in context.MyEntity
                                 where en.type == myTypeVar
                                 orderby context.Random()
                                 select en).AsEnumerable();
 

51voto

Jon Skeet Points 692016

Une façon simple de le faire est de commander en Guid.newGuid() mais alors la commande se fait sur le côté client. Vous pouvez être en mesure de convaincre EF de faire quelque chose d'aléatoire sur le côté serveur, mais ce n'est pas forcément simple.

La commande est O(n log n) de cours. Vous pouvez charger le tout dans une liste et ensuite mélanger la liste, qui est O(n). Qui va prendre un peu plus de code bien :)

EDIT: pour faire À la commande arrive sur le .NET le côté plutôt que de l'EF, vous avez besoin d' AsEnumerable:

IEnumerable<MyEntity> results = context.MyEntity
                                       .Where(en => en.type == myTypeVar)
                                       .AsEnumerable()
                                       .OrderBy(en => context.Random());

37voto

Drew Noakes Points 69288

Jon réponse est utile, mais en réalité, vous pouvez avoir la DB ne le commande à l'aide de Guid et Linq to entities (au moins, vous pouvez en EF4):

from e in MyEntities
orderby Guid.NewGuid()
select e

Cela génère le SQL ressemblant à:

SELECT
[Project1].[Id] AS [Id], 
[Project1].[Column1] AS [Column1]
FROM ( SELECT 
    NEWID() AS [C1],                     -- Guid created here
    [Extent1].[Id] AS [Id], 
    [Extent1].[Column1] AS [Column1],
    FROM [dbo].[MyEntities] AS [Extent1]
)  AS [Project1]
ORDER BY [Project1].[C1] ASC             -- Used for sorting here

Dans mes tests, à l'aide de Take(10) sur la requête (convertit TOP 10 dans SQL), la requête a couru de façon constante entre 0.42 et de 0,46 sec sur une table avec des 1,794,785 lignes. Aucune idée si SQL Server n'importe quel type d'optimisation sur ce ou si elle a généré un GUID pour chaque ligne de cette table. De toute façon, ce serait beaucoup plus rapide que de faire venir toutes ces lignes dans mon processus et en essayant de trier par là.

26voto

Michael Damatov Points 5453

La solution simple consisterait à créer un tableau (ou un List<T> ) et à randomiser ses index.

MODIFIER:

 static IEnumerable<T> Randomize<T>(this IEnumerable<T> source) {
  var array = source.ToArray();
  // randomize indexes (several approaches are possible)
  return array;
}
 

EDIT: Personnellement, je trouve la réponse de Jon Skeet plus élégante:

 var results = from ... in ... where ... orderby Guid.NewGuid() select ...
 

Et bien sûr, vous pouvez utiliser un générateur de nombres aléatoires au lieu de Guid.NewGuid() .

2voto

Fabrice Points 1581

Les solutions fournies ici s'exécutent sur le client. Si vous souhaitez que quelque chose s'exécute sur le serveur, voici une solution pour LINQ to SQL que vous pouvez convertir en Entity Framework.

0voto

Klinger Points 3096

Que dis-tu de ça:



    var randomizer = new Random();
    var results = from en in context.MyEntity
                  where en.type == myTypeVar
    			  let rand = randomizer.Next()
    			  orderby rand
    			  select en;
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X