簡體   English   中英

LINQ除了獲取所有行

[英]LINQ Except get all rows

我在包含DB Tables Objects的列表中使用Except方法,我具有DB中現有行的列表,以及來自app的值列表,我必須檢查這2個列表之間的增量並刪除/插入到DB中,我使用,但返回所有值。 碼:

public void UpdatePoints(IEnumerable<TBL_Points> selectedPoints, int id)
{

    List<TBL_Points> plistPointsFromDB = Context.TBL_Points.Where(x => x.Code == id).ToList();         
    List<TBL_Points> pRemoveItems = plistPointsFromDB .Except<TBL_Points>(selectedPoints.ToList()).ToList();
    List<TBL_Points> pAddItems = selectedPoints.ToList().Except<TBL_Points>(plistPointsFromDB).ToList();
}

pRemoveItems得到所有值plistPointsFromDBpAddItems得到所有值selectedPoints

Except另行指定,否則除外將使用調用EqualsGetHashCode的默認比較器。 這些,除非被覆蓋比較參考相等性,這意味着如果您有兩個不同的實例,即使它們具有相同的值,它們也不相等。 你需要 :

  • 覆蓋TBL_PointsEqualsGetHashCode
  • 或指定IEqualityComparer<TBL_Points>

閱讀更多內容:


同樣也不需要那么多的ToList()調用。

var fromDB = Context.TBL_Points.Where(x => x.Code == id).ToList(); 
var remove = fromDB.Except(selectedPoints);
var add = selectedPoints.Except(fromDB);

我剩下的一個是對數據庫執行查詢。 在其他情況下,最好使用IEnumerable<T>

前面的答案說明了如果您要檢查實際內容而不是相等性引用,則需要如何指定特殊比較器。

可能應該提到的一種補充:

如果您特別不需要List<T>Array<T> ,則應避免調用.ToList<T>().ToArray<T>() 使用其中任何一個時,都將復制現有集合中的所有項目,並將它們復制到新的項目中。 處理大型收藏集時,您的記憶並不會因此而感到開心。 同樣,處置新分配的內存所需的垃圾回收可能會給整體性能帶來巨大損失。 在我們的初級軟件開發人員沒有意識到這一點之前,我們曾在軟件中造成內存泄漏。

如果可以改用IEnumerable<T> ,則將延遲收集集合,因此不會(或幾乎沒有)分配額外的內存。

有時由於對索引的訪問或其他原因,您需要將集合轉換為List<T>Array<T> 即使這樣,您也應該將內存副本減少到最少。

CLR引用類型的默認相等語義是按對象標識進行比較的。 除非兩個引用引用相同的對象實例,否則它們將被視為不同的。

尤其是在此類情況下,需要設置操作的情況下,我們可能需要自定義此行為,為我們的對象提供語義,而不是引用語義。

有多種方法可以實現此目的。 我們可以在算法級別定義它,將自定義比較傳遞給Except方法。 或者我們可以在類型級別定義它,為所討論的set元素類型的所有實例定義相等性。 哪種方法最好,將部分取決於對象的使用方式以及是否可以修改定義集合元素類型的類的源代碼。

在回答中,Gilad Green提供了有關這些方法的性質和用例的Microsoft文檔的非常有用的參考。

在下面的示例中,我們使用自定義比較器定義相等性。

sealed class PointComparer: EqualityComparer<TBL_Points>
{
    public override bool Equals(TBL_Points x, TBL_Points y) => x.Code == y.Code;

    public override int GetHashCode(TBL_Points point) => point.Code.GetHashCode();
}

現在,我們需要實例化此比較器,並將其傳遞給Except如下所示

var pointsToAdd = selectedPoints
    .AsEnumerable()
    .Except(plistPointsFromDB, new PointComparer())
    .ToList();

請注意,我清理了命名(除了類型本身仍然很糟糕之外),並刪除了不必要的顯式類型使用。

另一種方法是為類型TBL_Points本身定義相等性(同樣需要重命名)

class TBL_Points: IEquatable<TBL_Points>
{
    public bool Equals(TBL_Points other) => Code == other?.Code;

    public sealed override bool Equals(object obj) => obj is TBL_Points o && Equals(o);

    public sealed override int GetHashCode() => Code.GetHashCode();

    public static bool operator ==(TBL_Points x, TBL_Points y) => x?.Equals(y);

    public static bool operator !=(TBL_Points x, TBL_Points y) => !(x == y);
}

上面為類型的所有用法定義了相等語義。 這很方便,因為我們不再需要創建比較對象的實例並將其傳遞給算法。 這也確保了所有用途之間的一致性。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM