2014-04-30 45 views
0

我有一個用戶添加的「標識」屬性,不需要重複。 (與數據庫ID不同)。編輯模型時忽略特定屬性的重複檢查

我已經添加下面的方法到我的視圖模型:

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) 
     { 
      GearContext db = new GearContext(); 
      if (db.Items.Where(p => p.Identification == this.Identification).Count() > 0) 
      { 
       yield return new ValidationResult("Identification already in use, please chose a different one. ", new[] { "Identification" }); 
      } 
     } 

的問題是,這樣可以防止我編輯我的模型。我希望只有在創建新條目時纔會進行驗證,而不是編輯。

我曾嘗試以下類型的編輯在我的控制器:

if (ModelState.IsValid) 
      { 
       var item = db.Items.Find(viewModel.ItemId); 
       Mapper.Map<ItemViewModel, Item>(viewModel, item); 
       if (TryUpdateModel(item, null, null, new string[] { "Identification" })) 
       { 
        db.SaveChanges(); 
        return RedirectToAction("Index"); 
       } 


      } 

也試過沒有「TryUpdateModel」在所有(簡單視圖模型=>模型和db.save)。

我想過在我的數據庫上下文中實現驗證方法,並只在item.State == EntityState.Added上運行它,但我相信我沒有訪問編輯過的模型屬性。

+0

將標識作爲相關表的唯一鍵的一部分並不容易,並將所有這些留給DBMS?即使你在MVC中實現這一點,控制檯應用程序或Windows服務仍然可以打破這種邏輯。把它放在db裏意味着什麼都不可能。 – barrick

+0

是否有可能首先用代碼定義唯一密鑰?另外,我不會有同樣的問題?我覺得這是我更新我的模型的方式,這可能是錯誤的(它根本不應該觸摸標識/標識)。 –

+0

以前肯定是不可能的;你不妨檢查一下EF6是否已經改變了。但是,要保留在MVC中,你有獨立的創建和編輯視圖嗎?推測如此。如果是這樣,請爲每個視圖分別提供不同的視圖模型,並在相關的GET請求進入時使用控制器創建這些實例。然後,Create模型可以包含此驗證,而Edit模型可以將此作爲不可變屬性,因此不會需要檢查。 – barrick

回答

1

要防止正在編輯的項目觸發驗證錯誤,請在您使用的查詢上添加對該ID的檢查。即改變這一行:

if (db.Items.Where(p => p.Identification == this.Identification).Count() > 0)

這樣:

if (db.Items.Where(p => p.ID != this.ID && p.Identification == this.Identification).Count() > 0)

順便說一句,我也想改變.Count() > 0.Any()以便查詢將尋找不超過1紀錄

此外,我真的認爲你應該考慮在DbContext中實施這個,以避免污染Model類DbContext。要做到這一點的方式在這裏描述:https://stackoverflow.com/a/18736484/150342

+0

這工作完美。現在也使用.Any()而不是Count()。我會查看你發佈的鏈接。謝謝! –

0

你可以做的是改變你的IValidatableObject方法,使它成爲一個集合。像這樣的東西

public ICollection<IValidatableObject> Validations { get; set; } 

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) 
{ 
    var valid = Enumerable.Empty<ValidationResult>(); 

    if (Validations != null) 
    { 
     valid = Validations.Aggregate(valid, (current, validate) => current.Concat(validate.Validate(validationContext))); 
    } 
    return valid; 
} 

您現在可以將驗證附加到IValidatableObject接口將調用的驗證集合。添加時,您可以添加您的重複支票。當您的編輯離開它或添加一個不同的驗證檢查。

這樣說我認爲重複鍵字段應該是數據庫的責任,而不是驗證方法。即使有了這個檢查,仍然有可能你有重複。在數據發送到SQL之前執行IValidatableObject檢查。因此,您可以讓兩個具有相同鍵的實體同時觸及此檢查,並且兩者都會通過,並且兩者都將被添加到SQL中。如果你真的想確保你將需要重寫dbcontexts SaveChanges方法

public override int SaveChanges() 
{ 
    var results = base.SaveChanges(); 

    // Run validation again for adds 
    PostValidation(); 

    return results; 
} 

只要你在一個事務中它尚未提交,您可以檢查SQL的重複鍵現在如果是這樣拋出錯誤並回滾事務。

+0

感謝您的回答。我將來很可能會使用一些有價值的信息。我接受科林的回答是因爲它非常簡單。 –