-1

次のコードでも、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;
    }
4

3 に答える 3

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()にオーバーライドする必要があることに注意してください。
    Equals()と演算子をオーバーロードするためのガイドライン==

    public class Facility {public string ID {get; セットする; } public string 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;
    }
    

    }



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();

また、注意すべき他のいくつかのこと:

  1. 名前を付けているのはガイドラインに従っていません。プロパティ名にアンダースコアを使用しないでください。IDはIdである必要があります。
  2. どちらの方法を使用する場合でもString.Equals(...)、StringComparison値の使用と指定を検討する必要があります。==投稿を短く読みやすくするために、文字列の等式比較を使用しました。
于 2013-03-08T18:52:54.910 に答える
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;
于 2013-03-08T18:53:53.663 に答える
1

Distinctは、デフォルトの等式比較子を使用して等式をチェックします。これは、参照の同等性を探していることを意味しますが、これは明らかにあなたの場合にはありません。

したがって、カスタムを使用する必要がありますIEqualityComparer(のオーバーロードを参照するか、の機能をaと: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();
}

私はおそらく、オーバーライドする等式演算子メソッドを使用します。

于 2013-03-08T18:56:29.037 に答える