2014-02-26 38 views
0

當前我正在嘗試爲我的DbContext上的ValidateEntity方法的一部分處理實體的唯一驗證。我試圖解決的問題是在同時添加多個實體時,在它碰到數據庫之前檢測到唯一的約束錯誤。當添加實體A和B以確保A和B不具有相同的名稱時,就是一個例子。目前,我已經申請了唯一索引,以便在最起碼的數據庫將處理它,我有以下的代碼,當A是已經在數據庫中,可以覆蓋:實體框架對本地和數據庫的唯一驗證

if (this.Components.Any(x => x.Id != item.Id && x.Name == item.Name)) 
{ 
    result.ValidationErrors.Add(new DbValidationError("Name", "There already exists another component with that name.")); 
} 

有什麼比這樣做以下簡單然後?

Expression<Func<Component, bool>> predicate = x => x.Name == item.Name; 

if (this.Components.Where(x => x.Id != item.Id).Any(predicate) || this.Components.Local.Where(x => x != item).Any(predicate.Compile())) 
{ 
    result.ValidationErrors.Add(new DbValidationError("Name", "There already exists another component with that name.")); 
} 

編輯

當「唯一密鑰」是由一個外鍵的情況下,是一個更爲複雜的局面。當對數據庫進行操作時,需要使用外鍵字段,但是當與本地緩存相對時,如果參考實體也剛剛添加,則由於它們都爲零,因此不能總是說ReferenceId == ReferenceId。檢查本地緩存的正確方法是否如下,或者是否需要加載引用,因爲在驗證過程中延遲加載是關閉的?

this.Components.Local.Any(x => x != item && x.Name == item.Name && x.ReferenceId == item.ReferenceId && x.Reference == item.Reference) 
+0

對我來說沒關係。我只會首先檢查本地集合,可能會節省數據庫往返。 –

+0

預編輯示例適用於以下簡單情況:唯一索引/鍵由非外鍵列組成,但在搜索中存在外鍵時會遇到問題,因爲它未設置爲非零直到保存後。 – cobywhite

回答

0

爲了解決我的問題並限制重用,我添加了以下擴展以幫助進行獨特的驗證。

public static bool UniqueCheck<TSource>(this DbSet<TSource> set, TSource item, Expression<Func<TSource, bool>> uniquePredicate) where TSource : class, IAuditEntity 
{ 

    var function = uniquePredicate.Compile(); 

    var localContains = set.Local.Where(x => x != item).Any(function); 
    if (localContains) return localContains; 

    var remoteContains = set.Where(x => x.Id != item.Id).Any(uniquePredicate); 

    return remoteContains; 
} 

public static bool UniqueCheckWithReference<TSource>(this DbSet<TSource> set, TSource item, Expression<Func<TSource, bool>> uniquePredicate, Expression<Func<TSource, bool>> referenceUniquePredicate) where TSource : class, IAuditEntity 
{ 
    var localContains = set.Local.Where(x => x != item).Where(uniquePredicate.Compile()).Where(referenceUniquePredicate.Compile()).Any(); 
    if (localContains) return localContains; 

    var remoteContains = set.Where(x => x.Id != item.Id).Where(uniquePredicate); 

    return false; 
} 

第二個函數處理唯一鍵由外鍵引用組成的情況。