2016-09-01 91 views
0

在下面的鏈接中,我問了一個關於如何確保一個字段沒有包含相同值的問題(例如,當一個字段上有一個唯一的約束,正確地導致C#拋出例外聲明)。隨着我收到的答案,它解決了這個問題,但提出了另一個問題。C#MVC CMS - 自定義遠程驗證

Ensuring another record does not already contain the same value for a field

主要的問題我現在是,當我創建一個新的視圖。驗證按預期工作。簡而言之 - 系統需要檢查ViewName和ViewPath(路由)是否都是唯一的,因此需要搜索DB。但是,當我編輯視圖時,驗證再次啓動(並且實際上不應該,因爲顯然視圖已經存在,因爲您正在編輯它)。

我的問題現在是我如何定製遠程驗證工作不同的編輯與創建。雖然我們不能編輯視圖的名稱來匹配現有的視圖,但我們也不應該因爲它與當前視圖相同而停止保存當前視圖。

下面是我的(希望由工具:-)生成)模型(即不是部分:

[MetadataType(typeof(IViewMetaData))] 
public partial class View : IViewMetaData { } 

public interface IViewMetaData 
{ 
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(DALResources), ErrorMessageResourceName = "ErrorRequiredField")] 
    [StringLength(50, ErrorMessageResourceType = typeof(DALResources), ErrorMessageResourceName = "ErrorLessThanCharacters")] 
    [Display(ResourceType = typeof(DALResources), Name = "ViewName")] 
    [Remote("IsViewNameAvailable", "Validation")] 
    string ViewName { get; set; } 

    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(DALResources), ErrorMessageResourceName = "ErrorRequiredField")] 
    [StringLength(400, ErrorMessageResourceType = typeof(DALResources), ErrorMessageResourceName = "ErrorLessThanCharacters")] 
    [Display(ResourceType = typeof(DALResources), Name = "ViewPath")] 
    [Remote("IsViewPathAvailable", "Validation")] 
    string ViewPath { get; set; } 

    [Display(ResourceType = typeof(DALResources), Name = "ViewContent")] 
    string ViewContent { get; set; } 
} 

的部分我有一個問題,是它被定義[遙控]驗證屬性如下:

[OutputCache(Location = OutputCacheLocation.None, NoStore = true)] 
public class ValidationController : Controller 
{ 
    private FRCMSV1Entities db = new FRCMSV1Entities(); 

    public JsonResult IsViewNameAvailable(View view) 
    { 
     bool isViewNameInvalid = db.View.Any(v => v.ViewName == view.ViewName && v.Id != view.Id); 

     if (!isViewNameInvalid) 
      return Json(true, JsonRequestBehavior.AllowGet); 

     string suggestedViewName = string.Format(UI_Prototype_MVC_Resources.ErrorViewAlreadyExists, view.ViewName); 

     for (int i = 1; i < 100; i++) 
     { 
      string altViewName = view.ViewName + i.ToString(); 
      bool doesAltViewNameExist = db.View.Any(v => v.ViewName == altViewName); 
      if (!doesAltViewNameExist) 
      { 
       suggestedViewName = string.Format(UI_Prototype_MVC_Resources.ErrorViewNotAvailableTry, view.ViewName, altViewName); 
       break; 
      } 
     } 
     return Json(suggestedViewName, JsonRequestBehavior.AllowGet); 
    } 

    public JsonResult IsViewPathAvailable(View view) 
    { 
     bool doesViewPathExist = db.View.Any(v => v.ViewPath == view.ViewPath && v.Id != view.Id); 

     if (!doesViewPathExist) 
      return Json(true, JsonRequestBehavior.AllowGet); 

     string suggestedViewPath = string.Format(UI_Prototype_MVC_Resources.ErrorViewAlreadyExists, view.ViewPath); 

     for (int i = 1; i < 100; i++) 
     { 
      string altViewPath = view.ViewPath + i.ToString(); 
      bool doesAltViewPathExist = db.View.Any(v => v.ViewPath == altViewPath); 
      if (!doesAltViewPathExist) 
      { 
       suggestedViewPath = string.Format(UI_Prototype_MVC_Resources.ErrorViewNotAvailableTry, view.ViewPath, altViewPath); 
       break; 
      } 
     } 
     return Json(suggestedViewPath, JsonRequestBehavior.AllowGet); 
    } 
} 

問題是,驗證需要在創建和編輯時都一樣。它只需要對編輯進行額外的檢查,以確保我們仍然引用相同的記錄,如果是這樣,則不需要顯示驗證消息,因爲沒有任何錯誤。

我的問題是: 1.我如何才能按預期工作。 2.我可以看到兩種方法幾乎完全相同,這違反了DRY原則。我怎樣才能使這個更通用,並簡化它。然而,第一個問題真的是我想要回答的問題,因爲重構一些不起作用的東西沒有意義。

欲瞭解更多信息,上面的代碼也通過以下鏈接的代碼編輯:

https://msdn.microsoft.com/en-us/library/gg508808(VS.98).aspx

感謝您的幫助。

回答

1

您需要添加一個參數才能傳遞模型的ID屬性爲AdditionalFields。假設其int Id,然後

[Remote("IsViewPathAvailable", "Validation", AdditionalFields = "Id")] 
public string ViewName { get; set; } 

和方法應該是

public JsonResult IsViewNameAvailable(string viewName, int? id) 

注意,在Edit視圖,您包括對Id屬性隱藏的輸入,所以它的價值將被張貼回來jquery.validate遠程函數。

然後,您可以檢查id參數是否爲null(即,它是新的)或具有值(它是現有的)並調整查詢以適合。

bool isViewNameInvalid; 
if (id.HasValue) 
{ 
    isViewNameInvalid = db.View.Any(v => v.ViewName == viewName && v.Id != id); 
} 
else 
{ 
    isViewNameInvalid = db.View.Any(v => v.ViewName == ViewName); 
} 

什麼正在發生的事情是,Remote只張貼ViewName屬性的值,因爲你的參數是模型,它與默認id值(0)初始化和您的查詢翻譯成Any(v => v.ViewName == viewName && v.Id != 0);

我也推薦使用視圖模型,而你的partial class

邊注:從生成suggestedViewName的代碼,你的期望很高的ViewName具有相同的值,這意味着您可能在內部進行衆多數據庫調用for循環。您可以考慮使用linq .StartsWith()查詢來獲取以您的ViewName值開頭的所有記錄,然後檢查循環中的內存集。

+0

你的答案奏效。再次感謝你的幫助。我會在單獨的評論中提出你的每個建議。使用Remote的建議確實減少了控制器中的代碼。我唯一不喜歡的是這是一個驗證問題,但它被設置爲一個控制器。我可能會嘗試找到另一種方法來做到這一點,並會感謝任何建議。 –

+0

ViewModels。我確實會使用ViewModel,但我現在只是對此進行原型設計,並想知道是否可以從中獲得功能系統。後來我會將它分成不同的層次,並且完成所有的好事,這就是ViewModel真正成爲必需的時候。但是,我同意,他們應該使用。 –

+0

.StartsWith() - 這是一個很好的建議。我現在就實現了它。再次感謝您的幫助Stephen。 –