C#MVC CMS – 自定义远程validation

在下面的链接中,我问了一个关于如何确保字段不包含相同值的问题(例如,当字段上存在唯一约束时,正确地导致C#在发出exception时抛出exception)。 根据我收到的答案,它解决了这个问题但提出了另一个问题。

确保另一条记录尚未包含字段的相同值

我现在面临的主要问题是当我创建一个新视图时。 validation按预期工作。 简而言之 – 系统需要检查ViewName和ViewPath(路由)是否都是唯一的,因此需要搜索数据库。

但是,当我编辑视图时,validation再次启动(实际上不应该这样做,因为很明显视图已存在,因为您正在编辑它)。

我现在的问题是如何自定义远程validation以使编辑与创建不同。 虽然我们不能编辑视图的名称以匹配现有视图,但我们也不应仅仅因为它与当前视图相同而停止保存当前视图。

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

[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; } } 

我遇到问题的部分是[Remote]validation属性,定义如下:

 [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  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  v.ViewPath == altViewPath); if (!doesAltViewPathExist) { suggestedViewPath = string.Format(UI_Prototype_MVC_Resources.ErrorViewNotAvailableTry, view.ViewPath, altViewPath); break; } } return Json(suggestedViewPath, JsonRequestBehavior.AllowGet); } } 

问题是,validation需要在创建和编辑时都一样。 它只需要对编辑进行额外的检查以确保我们仍然引用相同的记录,如果是这样,那么就没有必要显示validation消息,因为没有任何错误。

我的问题是:1。我如何按预期工作。 我可以看到两种方法都完全相同,这违反了DRY原则。 我怎样才能使它更通用并简化它。 然而,第一个问题实际上是我想要回答的问题,因为没有必要重构一些不起作用的东西。

有关更多信息,上面的代码也是以下链接的代码编辑:

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

谢谢你的帮助。

您需要添加一个参数以将模型的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

旁注:从生成ViewName的代码中,您期望很多ViewName具有相同的值,这意味着您可能在内部进行大量数据库调用for循环。 您可以考虑使用linq .StartsWith()查询来获取以ViewName值开头的所有记录,然后检查循环中的内存中集。