以下代码仍未返回DISTINCT结果集。我试图完成的等效SQL是SELECT DISTINCT LEFT(Fac_Name, 6) AS ID, LEFT(Fac_Name, 3) AS Fac_Name
public List<Facility> GetFacilities() {
var facilities = new List<Facility>();
facilities = _facilityRepository.GetAll().ToList();
var facReturnList =
facilities.Where(x => x.Fac_Name = "Something")
.OrderBy(x => x.Fac_Name).ToList();
var facReturnList2 =
facReturnList.Select(x =>
new Facility { ID = x.Fac_Name.Substring(0, 6),
Fac_Name = x.Fac_Name.Substring(0, 3) })
.Distinct().ToList();
return facReturnList2;
}
答案 0 :(得分:2)
您遇到的问题是您正在创建不同的引用值(将返回不同的哈希码),即使每个引用中的属性相等,实际引用本身也是不同的。
// fac1 and fac2 are the same reference, fac3 is a different reference.
var fac1 = new Facility { ID = "0", Fac_Name = "Hello" };
var fac2 = fac1;
var fac3 = new Facility { ID = "0", Fac_Name = "Hello" };
var facs = new List<Facility>() { fac1, fac2, fac3 };
foreach (var fac in facs.Distinct())
Console.WriteLine("Id: {0} | Name: {1}", fac.ID, fac.Fac_Name);
// OUTPUT
// Id: 0 | Name: Hello (NOTE: This is the value of fac1/fac2)
// Id: 0 | Name: Hello (This is the value of fac3)
要解决你的困境,你应该:
覆盖Object.GetHashCode()
和Object.Equals(Object)
方法。请注意,Distinct()
最终使用GetHashCode()来确定某些内容是否不同,但Equals(Object)
和GetHashCode()
应该一起覆盖。
Guidelines for Overloading Equals() and Operator ==
公共类设施 { 公共字符串ID {get;组; } 公共字符串Fac_Name {get;组; }
// This is just a rough example.
public override bool Equals(Object obj)
{
var fac = obj as Facility;
if (fac == null) return false;
if (Object.ReferenceEquals(this, fac)) return true;
return (this.ID == fac.ID) && (this.Fac_Name == fac.Fac_Name);
}
public override int GetHashCode()
{
var hash = 13;
if (!String.IsNullOrEmpty(this.ID))
hash ^= ID.GetHashCode();
if (!String.IsNullOrEmpty(this.Fac_Name))
hash ^= Fac_Name.GetHashCode();
return hash;
}
}
IEqualityComparer<T>
。
public class FacilityEqualityComparer : IEqualityComparer<Facility>
{
public bool Equals(Facility x, Facility y)
{
return (x.ID == y.ID) && (x.Fac_Name == y.Fac_Name);
}
public int GetHashCode(Facility fac)
{
var hash = 13;
if (!String.IsNullOrEmpty(this.ID))
hash ^= ID.GetHashCode();
if (!String.IsNullOrEmpty(this.Fac_Name))
hash ^= Fac_Name.GetHashCode();
return hash;
}
}
var facReturnList2 =
facReturnList.Select(x =>
new Facility { ID = x.Fac_Name.Substring(0, 6),
Fac_Name = x.Fac_Name.Substring(0, 3) })
.Distinct(new FacilityEqualityComparer()).ToList();
另外,还有一些需要注意的事项:
String.Equals(...)
并指定StringComparison值。我只是在字符串上使用==
相等比较来保持帖子简短易读。答案 1 :(得分:1)
所以问题是Enumerable.Distinct
方法使用默认的相等比较器 - 比较哈希码 - 所以无论属性值如何,它都将是一个不同的列表。为该类型构建一个相等比较器:
public class FacilityEqualityComparer : IEqualityComparer<Facility>
{
public bool Equals(Facility fac1, Facility fac2)
{
return fac1.ID.Equals(fac2.ID) && fac1.Fac_Name.Equals(fac2.Fac_Name);
}
public int GetHashCode(Facility fac)
{
string hCode = fac.ID + fac.Fac_Name;
return hCode.GetHashCode();
}
}
然后当你使用它时,请这样称呼:
var facReturnList2 =
facReturnList.Select(x =>
new Facility { ID = x.Fac_Name.Substring(0, 6),
Fac_Name = x.Fac_Name.Substring(0, 3) })
.Distinct(new FacilityEqualityComparer()).ToList();
return facReturnList2;
答案 2 :(得分:1)
Distinct使用默认的相等比较器来检查是否相等。这意味着它正在寻找引用相等,这显然不会出现在你的情况下。
因此,您需要使用自定义IEqualityComparer
(请参阅Distinct()
的重载,或者您可以使用Distinct()
复制GroupBy()
的功能First()
:
facReturnList.Select(x =>
new Facility { ID = x.Fac_Name.Substring(0, 6),
Fac_Name = x.Fac_Name.Substring(0, 3)
})
.GroupBy(x => new{x.ID, x.Fac_Name})
.Select(y => y.First())
.ToList();
您还可以在Facility
课程中覆盖Equals方法:
public override bool Equals(System.Object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
Facility objAsFacility = obj as Facility;
return Equals(objAsFacility);
}
protected bool Equals(Facility other)
{
if (other.Fac_Name == this.Fac_Name)
return true;
else return false;
}
public override int GetHashCode()
{
return this.Fac_Name.GetHashCode();
//Or you might even want to this:
//return (this.ID + this.Fac_Name).GetHashCode();
}
我可能会使用重写的等于运算符方法。