web-dev-qa-db-fra.com

Obtenez des enregistrements distincts en utilisant linq to entity

Bonjour, j'utilise linq to entity dans mon application. J'ai besoin d'obtenir des enregistrements distincts sur la base d'une valeur de colonne "Nom"

J'ai donc un tableau similaire comme vous pouvez le voir ci-dessous:

(User)
ID
Name
Country
DateCreated

Je dois sélectionner tous ces éléments mais uniques en fonction du nom (unique). Est-il possible d'accomplir en utilisant linq, si oui, montrez-moi comment.

var items = (from i in user select new  {i.id, i.name, i.country, i.datecreated}).Distinct();
25
Boommer

La méthode Distinct() ne fonctionne pas bien car elle n'envoie pas le prédicat DISTINCT SQL à la base de données. Utilisez à la place group:

var distinctResult = from c in result
             group c by c.Id into uniqueIds
             select uniqueIds.FirstOrDefault();

Le groupe de LINQ crée en fait des sous-groupes d'entités saisis par la propriété que vous indiquez:

Smith
  John
  Mary
  Ed
Jones
  Jerry
  Bob
  Sally

La syntaxe ci-dessus renvoie les clés, résultant en une liste distincte. Plus d'informations ici:

http://imar.spaanjaars.com/546/using-grouping-instead-of-distinct-in-entity-framework-to-optimize-performance

26
Dave Swersky

La manière purement LINQ qui se produit est de regrouper par nom, de sélectionner des groupes distincts par clé, puis de sélectionner en fonction de cela.

from i in user
group new {i.ID, i.Country, i.DateRecord} by i.Name into byNmGp
select byNmGp.First();

Edit: Entity Framework est bien sûr un fournisseur linq très populaire, mais il ne gère pas bien First() ici, bien que l'équivalent logique (dans ce cas) FirstOrDefault() fonctionne correctement. Je préfère First() lorsqu'il n'est pas forcé dans FirstOrDefault() par les limitations d'EF, car sa signification correspond mieux à ce qui est recherché ici.

Une autre façon consiste à définir une classe d'assistance:

private class MyRecord : IEquatable<MyRecord>
{
  public int ID;
  public string Name;
  public string Country;
  public DateTime DateCreated;
  public bool Equals(MyRecord other)
  {
    return Name.Equals(other.Name);
  }
  public override bool Equals(object obj)
  {
    return obj is MyRecord && Equals((MyRecord)obj);
  }
  public override int GetHashCode()
  {
    return Name.GetHashCode();
  }
}
/*...*/
var items = (from i in user select new MyRecord {i.ID, i.Name, i.Country, i.DateRecord}).Distinct();

Cela définit simplement distinctement différemment. Les performances diffèrent selon que le fournisseur de requêtes peut interpréter cette définition de l'égalité ou non. La commodité diffère selon que vous avez des requêtes LINQ similaires faisant à peu près la même chose ou non.

8
Jon Hanna

Vous pouvez utiliser quelque chose comme ceci:

var distinctReports = reports.Select(c => c.CompanyCode)
                             .Distinct()
                             .Select(c => reports.FirstOrDefault(r => r.CompanyCode == c))
                             .ToList();
2

Voici une autre variante que j'ai finalement utilisée, basée sur la réponse de Svetlana. Affiche un exemple de remplissage d'un contrôle GridView avec des valeurs uniques. Merci!

        dataGridView_AnalyzeTestSuites.DataSource = (
            from tr in _db.TestResults
            where tr.TaskId == taskId
            select new { TestSuiteName = tr.Test.TestSuite.Name }
            ).Distinct().ToList();
1
GrayDwarf

Bonjour, voici comment sélectionner des enregistrements distincts avec une jointure interne. J'espère que ça aide

var distinctrecords = 
(entity.Table.Join(entity.Table2, x => x.Column, y => y.Column, (x, y) => new {x, y})
             .Select(@t => new {@t.x.Column2, @t.y.Column3}))
             .GroupBy(t => t.Column2)
             .Select(g => g.FirstOrDefault());
1
Eugene