Reputation: 605
I have a query, which is defined like this, and I used it to generate a JSON output. The point is that, I have applied Distinct method to it, but it still shows duplicate items. For example, I have many items with value "Unclassifed", whereas I want only one of it, same goes for some other values. Here is my query:
var results = db.Users.OfType<Business>()
.Where(b => b.StateID == state && (term == null || b.Description.ToLower().Contains(term.ToLower())))
.Distinct().Select(x => new { id = x.StateID, value = x.Description }).Take(5).ToList();
Any idea, how to fix it? I guess I need to specifically apply Distinct to the value somehow.
Upvotes: 0
Views: 113
Reputation: 7747
I suspect you need to switch your Distinct
and Select
calls. Distinct
will compare more fields than you are probably expecting given your projection, which may mean fields other than the ones you actually want to compare on are being compared. Calling Select
first will reduce the number of fields that are compared to generate the distinct list.
i.e.
var results = db.Users.OfType<Business>()
.Where(b => b.StateID == state && (term == null || b.Description.ToLower().Contains(term.ToLower())))
.Select(x => new { id = x.StateID, value = x.Description })
.Distinct()
.Take(5)
.ToList();
Upvotes: 4
Reputation: 91
.Distinct()
without providing a manual comparer will use the default comparer of the processed type which will ultimately use the .Equals()
and .GetHashCode()
of your Business
class.
So unless you have overridden those methods .Distinct()
will only remove reference-wise duplicates.
Upvotes: 0
Reputation: 219057
.NET has no way of knowing how you want to determine "equality" in your objects. By default, equality of reference types is based only on reference equality, so all of your objects are already distinct by default.
You can provide a custom equality comparer to Distinct()
. For example, if you're just comparing on a .Name
property to determine uniqueness, it might look something like this:
class BusinessComparer : IEqualityComparer<Business>
{
public bool Equals(Business x, Business y)
{
if (Object.ReferenceEquals(x, y))
return true;
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
return x.Name == y.Name;
}
public int GetHashCode(Business business)
{
if (Object.ReferenceEquals(business, null))
return 0;
int hashBusinessName = business.Name == null ? 0 : business.Name.GetHashCode();
return hashProductName;
}
}
If this equality is core business logic and not just used in this particular comparison then you might even implement Equals
and GetHashCode
on Business
itself so that equality comparison can be used elsewhere. Just be aware that could be a breaking change to existing code which already assumes referential equality.
Upvotes: 1
Reputation: 13794
Distinct()
returns distinct elements from a sequence by using the default equality comparer to compare values. so you should create BusinessEqualityComparer class should Implement IEqualityComparer Interface
class BusinessEqualityComparer : IEqualityComparer<Business>
{
public bool Equals(Business b1, Business b2)
{
if (b1.ID == b2.ID)
{
return true;
}
else
{
return false;
}
}
public int GetHashCode(Business business)
{
int hCode = business.ID ^ business.ID ^ business.ID;
return hCode.GetHashCode();
}
Upvotes: 0
Reputation: 7934
Business
class needs to override object.Equals
and object.GetHashCode
methods and implemented IEquatable<T>
before the Distinct
method will function correctly.
See MSDN examples: Enumerable.Distinct Method (IEnumerable)
Upvotes: 0