2010-08-22 9 views
25

Salut J'utilise linq to entity dans mon application. Je dois obtenir des documents distincts sur la base d'une valeur de la colonne « Nom »Récupère des enregistrements distincts en utilisant linq to entity

J'ai une table similaire comme vous pouvez le voir ci-dessous:

(User) 
ID 
Name 
Country 
DateCreated 

J'ai besoin pour sélectionner tous ces éléments mais uniques à base de Nom (unique) Est-il possible d'accomplir en utilisant linq, si oui, s'il vous plaît montrez-moi comment.

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

Vous avez impliqué qu'il y a plusieurs enregistrements pour chaque 'Nom'. Si cela est vrai, la question devrait également indiquer comment choisir les autres champs (id, country, datecreated). Par exemple, pour chaque nom, voulez-vous l'enregistrement avec le datecreated minimum? – crokusek

Répondre

27

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

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

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

Smith 
    John 
    Mary 
    Ed 
Jones 
    Jerry 
    Bob 
    Sally 

La syntaxe retourne au-dessus des touches, ce qui dans une liste distincte. Plus d'informations ici:

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

+0

J'ai oublié que je devais utiliser la jointure interne à une autre table. Pourriez-vous me montrer s'il vous plaît comment changer le code? – Boommer

+3

Distinct() fait en fait que le SQL inclut le prédicat DISTINCT. Pourquoi pensez-vous que non?Bien sûr, cela ne fonctionnera que si vous travaillez encore avec IQUeryables .. mais c'est le cas. –

+0

Cette réponse m'a sauvé: D Merci, Dave! – programad

8

La manière purement LINQ qui se produit est de groupe par nom, sélectionner des groupes distincts par clé, puis sélectionnez sur cette base.

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 First() bien ici, bien que la logique équivalente (dans ce cas) FirstOrDefault() fonctionnera bien. Je préfère First() lorsqu'il n'est pas forcé dans FirstOrDefault() par les limitations d'EF, parce que sa signification correspond mieux à ce qui est recherché ici.

Une autre façon est de définir une classe d'aide:

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 différemment distincts. Les performances diffèrent selon que le fournisseur de requêtes peut interpréter ou non cette définition de l'égalité. La commodité varie selon que vous avez des requêtes LINQ similaires qui font la même chose ou pas.

+0

Comment puis-je accomplir plusieurs tables à l'aide de la jointure? – Boommer

+0

'i à partir de iSrc rejoindre j de jSrc sur i.someField est égal à j.someField'. Ce n'est pas la même question que celle-ci, il peut être préférable de poser des questions distinctes plutôt que d'ajouter et d'ajouter au même. Les gens regardent des questions basées sur la question, et connaître la réponse à l'une n'implique pas toujours de connaître la réponse à une autre. –

+0

U m'a mal compris. Je demande comment grouper ou juste comment accomplir la même chose que je demande mais en utilisant la jointure interne (plusieurs tables). – Boommer

1

Bonjour, voici comment vous pouvez sélectionner des enregistrements distincts avec jointure interne. Hope it helps

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()); 
2

Vous pouvez utiliser quelque chose comme ceci:

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

Voici une autre variante que je fini par utiliser ce qui a été basé sur l'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(); 
+0

Ceci est la bonne réponse, puisque l'OP a posé des questions sur la syntaxe linq, pas lambda. –

Questions connexes