2015-01-13 31 views
0

在將實體保存到數據庫之前,我需要檢查重複條目。以下是我目前的代碼在性能方面,檢查重複實體的好方法

if (db.Product.Any(x => x.Code == entity.Code)) 
{ 
    error.Add('Duplicate code'); 
} 

if (db.Product.Any(x => x.Name == entity.Name)) 
{ 
    error.Add('Duplicate name'); 
} 

if (db.Product.Any(x => x.OtherField == entity.OtherField)) 
{ 
    error.Add('Duplicate other field'); 
} 

上面的代碼的問題是,它使3分貝調用來驗證實體。這個表格有數百萬條記錄,這個應用程序將被千用戶使用。所以這會嚴重損害業績。我可以讓它一個查詢雖然

if (db.Product.Any(x => x.Code == entity.Code || x.Name == entity.Name || x.OtherField == entity.OtherField)) 
{ 
    error.Add('Duplication found'); 
} 

第二個代碼的問題是,我不知道哪個字段是重複的。

這樣做的更好方法是什麼?我應該只依賴於數據庫中的唯一約束嗎?然而,來自數據庫的錯誤是醜陋的。

編輯

我需要顯示所有的錯誤給用戶如果超過1個重複的領域。 考慮這種情況:如果重複字段是代碼和名稱。如果我告訴用戶代碼已經存在,那麼他會更改代碼並嘗試再次保存它。然後顯示第二個錯誤(名稱字段)。在成功保存之前,它使用戶保存了幾次。

回答

2

如果您對本領域NameCodeOtherField指標,然後重複檢查並不會太長,但仍然會3個調用數據庫,而不是爲1.

在這種情況下通常的解決方案是計數重複。然後,如果count等於0,則沒有重複。

Here你會發現一些黑客做到這一點。

短的例子:

var counts =(
    from product in db.Products 
    group product by 1 into p 
    select new 
    { 
     Name = p.Count(x => x.Name == name), 
     Code = p.Count(x => x.Code == code), 
     OtherField = p.Count(x => x.OtherField == otherFields) 
    } 
).FirstOrDefault(); 

if (counts.Name > 0) 
    error.Add("Duplicate name"); 

if (counts.Code > 0) 
    error.Add("Duplicate code"); 

更新:它似乎有可能解決問題更簡單的方法:

var duplicates =(
    from product in db.Products 
    group product by 1 into p 
    select new 
    { 
     Name = p.Any(x => x.Name == name), 
     Code = p.Any(x => x.Code == code), 
     OtherField = p.Any(x => x.OtherField == otherFields) 
    } 
).FirstOrDefault(); 

if (duplicates.Name) 
    error.Add("Duplicate name"); 
+0

我非常喜歡這種方法。但你覺得這個表現怎麼樣?沒有計數掃描表中的所有記錄? – Reynaldi

+0

大多數數據庫引擎都針對計數進行了優化,但「Any」通常更好,因爲它停止在找到的第一條記錄。 –

+0

@Reynaldi您需要在'Products'表中爲'Name','Code'和'OtherField'字段創建索引,然後SQL可以在O(log N)時間內對行進行計數。 –

0

1 - 您可以選擇重複的實體

var product = db.Product.FirstOrDefault(x => x.Code == entity.Code 
               || x.Name == entity.Name 
               || x.OtherField == entity.OtherField); 

if (product == null) 
;//no duplicates 

if (product.Code == entity.Code) 
{ 
    error.Add('Duplicate code'); 
} 

if (product.Name == entity.Name) 
{ 
    error.Add('Duplicate name'); 
} 

if (product.OtherField == entity.OtherField) 
{ 
    error.Add('Duplicate other field'); 
} 

2 - 您可以創建存儲過程插入併爲您在它的重複;

編輯: OK,你可以寫這樣的事情

var duplicates = (from o in db.Products 
       select new 
       { 
        codeCount = db.Products.Where(c => c.Code == entity.Code).Count(), 
        nameCount = db.Products.Where(c => c.Name == entity.Name).Count(), 
        otherFieldCount = db.Products.Where(c => c.OtherField == entity.OtherField).Count() 
       }).FirstOrDefault(); 

這將選擇每個數的領域複製。 有一點需要注意:無論如何,你應該在數據庫中有唯一的約束,因爲當你驗證和保存數據時,在你插入它們之前可能會插入另一個包含這些值的行。

+0

IF成千上萬的代碼是有那麼你會怎麼辦? –

+0

@Giorgi我也試過#1。但是,即使有多個字段重複,它也只會顯示1個錯誤(代碼/名稱/其他字段)。存儲過程方法似乎是我猜的更好的選擇。 – Reynaldi

+0

@Reynaldi,我編輯了我的答案.. –

1

你可以做這樣的事情:

string duplicateField; 

    bool validationResult = db.Product.Any(x => { 
      if(x.Code == entity.Code){ 
      duplicateField = "Code"; 
       return true; 
      } 
    // Other field checks here 

} 

if(validationResult){ 
// Error in field <duplicateField> 
} 
+0

如果我沒有錯,那麼代碼塊將無法使用enitity框架。 –