2

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' ?

Phill Healey
  • 3,084
  • 2
  • 33
  • 67

6 Answers6

4

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();
Nomad101
  • 1,688
  • 11
  • 16
2

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.

hvaughan3
  • 10,955
  • 5
  • 56
  • 76
0

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.

Community
  • 1
  • 1
Matt
  • 2,984
  • 1
  • 24
  • 31
  • Yes, I beleive it is. Thats why I posted. Hopefully to find a way to do distinct on just the second field. The link looks like it has potential. Thanks. – Phill Healey Apr 30 '13 at 12:26
  • Actually, that link doesnt work unfortunately. Also, checking in the CRM the fields arent duplicated. So no idea how I can select a distinct on the results. – Phill Healey Apr 30 '13 at 13:13
  • Can you supply more code to give us an example that exhibits the issue? What are the results that are causing the problem? Can you reproduce it if you swap out the entity context with a simple list that contains the two objects that are the problem? – Matt Apr 30 '13 at 23:26
  • Basically its a list of regional offices, and their corresponding Id in the CRM. For some reason one of the branches has another instance that has a seperate id but the same name. I cant actually see this other branch in the CRM so it looks like some sort of relic attached to somebody's account. So whilst all the returned branch Ids are different their are two branch names the same. I need to eliminate this extra one but dont want to hard code it(eg do a manual removal of this one). – Phill Healey Apr 30 '13 at 23:40
  • Do you mean that the BranchTagCodes are different, but the BranchTags are the same for the two results? – Matt May 01 '13 at 02:25
  • This means that the distinct call is performing correctly, the two results are different. You could implement an equality comparer that only looks at the BranchTags, but it would select one of the records, and you would throw the other BranchTagCode away. You must decide which one you want to keep... – Matt May 01 '13 at 23:29
  • I did say this in my OP to be fair. Thats what my post was about. – Phill Healey May 01 '13 at 23:47
  • Yeah, ok, so you need to build an IEqualityComparer implementation that selects the correct BranchTagCode. Given 2 records with the same BranchTag, pick the correct one. Which one is the correct one for you? – Matt May 02 '13 at 01:35
0

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.

Darren Lewis
  • 8,338
  • 3
  • 35
  • 55
0

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.

TPG
  • 2,811
  • 1
  • 31
  • 52
0

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

roncansan
  • 2,310
  • 6
  • 27
  • 34