How to use Distinct() or Groupby() in a list that returns an anonymous type?

Asked

Viewed 266 times

1

I’m doing a select on the bench to bring the IdNavio and Navio, but I don’t want to bring the repeated.

I’m trying to use the methods Distinct() and GroupBy(), but they’re not working, I’m using the namespace System.Linq.

Example:

var listaDeNavios = Context.VWProgramacaoEmbarque
                           .Select(e => new { IdNavio = e.IdNavio, Navio = e.Navio });

Can you do it using these methods? Or is there another way for this type?

  • What’s the matter? He keeps bringing duplicates?

  • @Gabrielcoletta Continues to bring duplicate.

  • Idnavio is a primary key?

  • @Gabrielcoletta Actually this select is based on a View of the bank that has several Ids, one of them is the Ship Id. Could that be the problem ? for being a view ?

  • theoretically not, the problem is if it is a primary key. Can I say it is? If it is already know the problem

  • @Gabrielcoletta Yes, it is a primary key.

  • @samuelrvg You want to distinguish by a property or by the two?

  • @LINQ by Ship Id only, but if possible by the two also looks interesting.

  • You know that one Id is always different from the other, right? That’s the main problem of your Distinct().

Show 4 more comments

2 answers

2


If you want to make a distinct by property NavioId, you can group the results by this property and then use the method Distinct.

Usually I prefer to do an extension method for this

public static class QueryableExtensions
{
    public static IQueryable<TSource> DistinctBy<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector)
    {
        return source.GroupBy(keySelector).Select(x => x.FirstOrDefault());
    }
}

The use would be like this

var listaDeNavios = Context.VWProgramacaoEmbarque
                       .Select(e => new { IdNavio = e.IdNavio, Navio = e.Navio })
                       .DistinctBy(e => e.IdNavio);
  • It did not work when I turn into . Tolist() generates the following error: Message "Oracle 11.2.0.4.0 does not support APPLY" string - Related to Oracle, I will search for this error to understand better.

  • 1

    @samuelrvg Did not know that your bank is Oracle, you will not be able to do Groupby with Oracle 11 because the query that the RU generates has a OUTTER APPLY and your database does not support it.

  • I understand, this question rightly talks about this https://stackoverflow.com/questions/29705013/linq-to-entities-group-by-outer-apply-oracle-11-2-0-does-not-support-appl

  • @samuelrvg Exactly, I think the best idea for you is to create a trial to bring the data already with distinct. Btw, I’m not sure how to act with your question, because (in this case) the database being Oracle changes the whole path of the answers and this has not been specified.

  • I understand, in this case I will accept your answer as a solution, because the problem is that oracle 11g does not support this type of query.

1

The problem is your Idnavio is a unique value. The Enumerable.Distinct() uses Object methods to do its job. In the case of anonymous type the compiler will override the Object.Equals() and the Object.GetHashCode() and will compare all values of your type. Since your Idnavio will always have different values among themselves, the same will always be different.

The simple solution would be a Iequalitycomparer, but he is not an employee since you have an anonymous type and only using reflection you could know which properties will participate in the comparison, something similar to the one exemplified here:

https://www.codeproject.com/Articles/94272/A-Generic-IEqualityComparer-for-Linq-Distinct

So the best solution, in my humble opinion, is for you to create a Command class and overwrite Object.Equals() and Object.GetHashCode(), so implementing Distinctby would be much simpler:

public class NavioComparer : IEqualityComparer<NavioCommand>
{
    public bool Equals(NavioCommand first, NavioCommand second)
    {
        return first.Navio.Equals(second.Navio);
    }

    public int GetHashCode(NavioCommand obj)
    {
        return obj.Navio.GetHashCode();
    }
}

Other addenda:

  • Morelinq’s Distinctby employee, however he works with Ienumerable, not Iqueryable, so his Distinct would run in memory, not in the database.
  • You could also implement your own Distinctby that accepts a Iqueryable (LINQ example).

Browser other questions tagged

You are not signed in. Login or sign up in order to post.