Phill Healey
Phill Healey

Reputation: 3180

LINQ query returns duplicate despite Distinct()

Ive got the following query that binds to a DropDownList;

if (!Page.IsPostBack)
        {
            var branchTags =
                (
                    from t in context.ContactSet
                    orderby t.py3_BranchArea
                    where t.py3_BranchArea != null
                    select new
                    {
                        BranchTagCode = t.py3_BranchArea,
                        BranchTag = (t.FormattedValues != null && t.FormattedValues.Contains("py3_brancharea") ? t.FormattedValues["py3_brancharea"] : null)
                    }
                ).Distinct();
            ddlBranchTags.DataSource = branchTags;
            ddlBranchTags.DataBind();
        }

For some reason it still ourputs 2 rows that are visually the same. It might be the case that there are two enitites in the CRM with the same name. But, if Im using distinct on the query and only returning the 'py3_brancharea' then surely the Distinct should be run on the actual records returned?

So, this suggests to me -and my limited LINQ knowledge- that its because of the line:

BranchTagCode = t.py3_BranchArea

But, this needs to be called to make it possible to call the FormattedValues.

How then do I get a distinct set of results based purely on 'BranchTag' ?

Upvotes: 2

Views: 3763

Answers (6)

Nomad101
Nomad101

Reputation: 1698

If Distinct() is not working it is possibly a problem with the particular classes gethashcode() or equals() override methods, which are either not set up correctly or omitted entirely. In a custom class you will most likely need to specify these overrides to get Distinct() and other like methods to function correctly.

You could try to use a where or any clause to differentiate between duplicates as well. Which could be a work around for the Distinct() issues.

To further explain how to set up the Distinct() Method with custom classes. You will need to within the class that you are searching through set the override methods GetHashCode() and Equals(). These or Object level methods that should be in every single class no matter what. To start head to the class in question and type this:

public override bool Equals(object obj) then public override int GetHashCode()

Lets say you have this simple class before the overrides:

class foo{
   int H {get;set;}
   public foo(int _h){
        H = _h;
   }
}

It would now look like this:

class foo{
   int H {get;set;}
   int K {get;set;}

   public override bool Equals(object obj){
         if(obj == null) return false;
         foo test = (foo)obj);
         if(test == null) return false;
         
         if(this.H == obj.H && this.K == obj.K) return true;
   }
   public override int GetHashCode(){
         int hashH = H.GetHashCode();
         int hashK = K.GetHashCode();

         return hashH ^ hashK;
   }

   public foo(int _h){
        H = _h;
   }
}

Now you could use Distinct() on Ienumerable types containing the foo class like so:

 List<foo> FooList = new List<foo>(Collection of 9 Foos);
 var res = FooList.Distinct();

Upvotes: 4

roncansan
roncansan

Reputation: 2380

Another possibility it that the Entity Object has a define key that is not unique.

Upvotes: 0

TPG
TPG

Reputation: 3209

I changed my code from

.Distinct().ToList();

to

.ToList().Distinct().ToList();

and now it's able to avoid the duplicate. Not sure what's the reason behind.

Upvotes: 0

hvaughan3
hvaughan3

Reputation: 11105

Another, much more simple way that worked for me, but may not work in all situations, is using this guys method ( GroupBy() and First()):

Finding Distinct Elements in a List

He creates a List<Customer> customers with FirstName and LastName. Then groups them all by FirstName and grabs the first element from each group!

`
List< Customer > customers = new List< Customer >;
{
    new Customer {FirstName = "John", LastName = "Doe"},
    new Customer {FirstName = "Jane", LastName = "Doe"},
    new Customer {FirstName = "John", LastName = "Doe"},
    new Customer {FirstName = "Jay",  LastName = null},
    new Customer {FirstName = "Jay",  LastName = "Doe"}
};
`

Then:

`
var distinctCustomers = customers.GroupBy(s => s.FirstName)
                                 .Select(s => s.First());
`

In my situation, I had to use FirstOrDefault() though.

Upvotes: 2

Darren Lewis
Darren Lewis

Reputation: 8488

The default equality comparison for anonymous types is case sensitive. Do the returned values you expect have different casing? As Matt suggested you may want to look at a custom IEqualityComparer implementation on a custom class otherwise.

Upvotes: 0

Matt
Matt

Reputation: 3014

Is it possible that the two results are different, do they have the same branch tag code and branch tag?

You could implement a custom equality comparer and pass it to distinct() so that it only compares the field that you want? it's a bit more difficult because of the anonymous type in your select statement, but this answer has a way around that.

Upvotes: 0

Related Questions