2013-11-25 60 views
1

我一直在一個項目工作一段時間來解析csv文件中的條目列表並使用該數據來更新數據庫。C#比較複雜的對象返回差異列表

對於每個條目,我創建一個新的用戶實例,我把它放在一個集合中。現在我想迭代該集合並將用戶條目與數據庫中的用戶進行比較(如果存在)。我的問題是,如何將用戶(條目)對象與用戶(db)對象進行比較,並返回具有差異的列表?

對於從數據庫中生成例如以下類:

public class User 
{ 
    public int ID { get; set; } 
    public string EmployeeNumber { get; set; } 
    public string UserName { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public Nullable<int> OfficeID { get; set; } 

    public virtual Office Office { get; set; } 
} 

public class Office 
{ 
    public int ID { get; set; } 
    public string Code { get; set; } 

    public virtual ICollection<User> Users { get; set; } 
} 

爲了一些查詢保存到數據庫中,我只是填補我可以從CSV文件中檢索的屬性,所以ID的(例如)不可用於平等檢查。

有沒有什麼辦法可以比較這些對象,而無需爲每個屬性定義規則並返回修改的屬性列表?我知道這個問題似乎與以前的一些帖子類似。我已經閱讀了很多,但由於我對編程沒有經驗,所以我會很感激一些建議。

從我讀過的內容中,我應該將'一般性比較屬性'與'忽略使用數據註釋的屬性'和'返回CompareResults列表'結合起來?

+1

爲了更好地理解您的問題,如果您的CSV文件中沒有該ID,那麼您將用什麼作爲用戶的唯一標識符?即您何時決定不創建新條目? –

+0

噢,對不起,我遺漏了一些屬性來將這個例子稍微扁平化。我將編輯示例。唯一標識符是一個員工編號,這對於決定是否在數據庫中創建新用戶當然是必需的。 – Leegaert

+0

你見過[比較兩個對象並找到差異](http://stackoverflow.com/questions/4951233/compare-two-objects-and-find-the-differences)? –

回答

0

有一些可以解決這個幾種方法:
方法#1是爲CSV文件的內容創建單獨的DTO樣式類。雖然這涉及到創建具有許多類似字段的新類,但它將CSV文件格式從數據庫中分離出來,並讓您能夠在不影響其他部分的情況下更改它們。爲了實現比較,你可以創建一個Comparer類。只要類幾乎相同,比較就可以從DTO類中獲取所有屬性並動態實現比較(例如,通過創建和評估包含類型爲Equal的BinaryExpression的Lambda表達式)。
方法#2避免了DTO,但使用屬性來標記屬於比較的屬性。您需要創建一個您分配給相關屬性的自定義屬性。在比較中,您將分析該類的所有屬性並過濾出用該屬性標記的屬性。爲了比較屬性,你可以使用與#1相同的方法。這種方法的缺點是你將比較邏輯與數據類緊密地結合在一起。如果你需要實現幾個不同的比較,你會用這些屬性混淆數據類。
當然,#1會比#2產生更大的努力。我明白,這不是你正在尋找的,但也許有一個單獨的,強類型的對比課也是一個可以考慮的方法。
更多有關動態比較算法的詳細信息:它基於反射以獲取需要比較的屬性(取決於您獲得DTO屬性或相關數據類的屬性的方法)。一旦擁有屬性(對於DTO,屬性應該具有相同的名稱和數據類型),您可以創建LamdaExpression並動態編譯和評估它。下列行示出了示例代碼的摘錄:

public static bool AreEqual<TDTO, TDATA>(TDTO dto, TDATA data) 
{ 
    foreach(var prop in typeof(TDTO).GetProperties()) 
    { 
     var dataProp = typeof(TDATA).GetProperty(prop.Name); 
     if (dataProp == null) 
      throw new InvalidOperationException(string.Format("Property {0} is missing in data class.", prop.Name)); 
     var compExpr = GetComparisonExpression(prop, dataProp); 
     var del = compExpr.Compile(); 
     if (!(bool)del.DynamicInvoke(dto, data)) 
      return false; 
    } 
    return true; 
} 

private static LambdaExpression GetComparisonExpression(PropertyInfo dtoProp, PropertyInfo dataProp) 
{ 
    var dtoParam = Expression.Parameter(dtoProp.DeclaringType, "dto"); 
    var dataParam = Expression.Parameter(dataProp.DeclaringType, "data"); 
    return Expression.Lambda(
     Expression.MakeBinary(ExpressionType.Equal, 
      Expression.MakeMemberAccess(
       dtoParam, dtoProp), 
      Expression.MakeMemberAccess(
       dataParam, dataProp)), dtoParam, dataParam); 
} 

對於全樣本,請參閱本link。請注意,這種動態方法只是一個簡單的實現,有待改進的餘地(例如,不檢查屬性的數據類型)。它也只是檢查是否相等,不收集不相等的屬性;但這應該很容易轉移。
雖然動態方法很容易實現,但運行時錯誤的風險比強類型方法要大。

+0

感謝您的輸入Markus。我從單獨的DTO課程開始,我會再看看它。你能否詳細說一下比較級課程,你有沒有讓我失望。 – Leegaert

+0

我已將我的答案擴展爲顯示簡單的動態比較。 – Markus

+0

感謝您的示例。我必須承認GetComparisonExpression部分高於我的頭。我會和它一起玩一下,看看我是否可以繞過它,稍後我會發佈一個更新。 – Leegaert