2011-10-12 65 views
0

我正在使用MVC3的项目。我首先创建了一个数据库(具有必要的约束如PK和FK),并使用ADO.NET实体数据模型将此数据库添加到我的web应用程序中。一切似乎工作正常,但我不能使验证灵活。这里有一些代码来澄清我的问题。自定义验证MVC 3与实体数据模型


编辑:添加了视图+正确的模型。该版本没有导入数据库,但结果相同。


--Models ----

namespace CustomValidation.Models 
{ 
    public class Person : IValidatableObject 
    { 

    public int Id { get; set; } 
    [Required] 
    public String FirstName { get; set; } 
    [Required] 
    public String LastName { get; set; } 

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) 
    { 
     if (String.IsNullOrEmpty(FirstName)) 
     { 
      var field = new[] { "FirstName" }; 
      yield return new ValidationResult("Firstname can't be null", field); 
     } 
    } 
} 
} 



namespace CustomValidation.Models 
{ 
    public class Address : IValidatableObject 
    { 

    public int Id { get; set; } 
    [Required] 
    public String Streetname { get; set; } 
    [Required] 
    public String Zipcode { get; set; } 
    [Required] 
    public String City { get; set; } 
    [Required] 
    public String Country { get; set; } 
    public Person Person { get; set; } 

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) 
    { 
     if (String.IsNullOrEmpty(Streetname)) 
     { 
      var field = new[] { "Streetname" }; 
      yield return new ValidationResult("Streetname can't be null", field); 
     } 
    } 
} 
} 


public class MasterModel 
{ 
    public List<Address> Addressess { get; set; } 
    public Person Person { get; set; } 
    } 
} 





namespace CustomValidation.Models 
{ 
    public class DBEntities : DbContext 
    { 
    public DbSet<Person> People { get; set; } 
    public DbSet<Address> Addressess { get; set; } 
    } 
} 

---- ----控制器

namespace CustomValidation.Controllers 
{ 
public class HomeController : Controller 
{ 
    public ActionResult Index() 
    { 
     MasterModel Model = new MasterModel(); 
     Model.Person = new Person(); 
     Model.Addressess = new List<Address>(); 
     Model.Addressess.Add(new Address()); 
     Model.Addressess.Add(new Address()); 
     return View(Model); 
    } 


    [HttpPost] 
    public ActionResult Index(MasterModel Model) 
    { 
     DBEntities _db = new DBEntities(); 
     if (TryValidateModel(Model.Person)) 
     { 
      _db.People.Add(Model.Person); 
      _db.SaveChanges(); 
     } 
     else 
     { 
      return View(Model); 
     } 

     for (int i = 0; i < Model.Addressess.Count; i++) 
     { 
      if (!String.IsNullOrEmpty(Model.Addressess[i].Country)) 
      { 
       if (TryValidateModel(Model.Addressess[i])) 
       { 
        Model.Addressess[i].Person = Model.Person; 
        _db.Addressess.Add(Model.Addressess[i]); 
        _db.SaveChanges(); 
       } 
       else 
       { 
        return View(Model); 
       } 
      } 
     } 
     return RedirectToAction("Index"); 
    } 
} 

这是我的观点:

@model CustomValidation.Models.MasterModel 
@{ 
ViewBag.Title = "Index"; 
} 

<h2>Create</h2> 

@using (Html.BeginForm()) { 
@Html.ValidationSummary(true) 
<fieldset> 
<legend>Person</legend> 
<div class="editor-label"> 
@Html.LabelFor(m => Model.Person.FirstName) 
@Html.EditorFor(m => Model.Person.FirstName) 
</div> 
<div class="editor-label"> 
@Html.LabelFor(m => Model.Person.LastName) 
@Html.EditorFor(m => Model.Person.LastName) 
</div> 

</fieldset> 
for (int i = 0; i < Model.Addressess.Count; i++) 
{ 
<fieldset> 
    <legend>Address</legend> 

    <div class="editor-label"> 
     @Html.LabelFor(model => Model.Addressess[i].Streetname) 
    </div> 
    <div class="editor-field"> 
     @Html.EditorFor(model => model.Addressess[i].Streetname) 
     @Html.ValidationMessageFor(model => Model.Addressess[i].Streetname) 
    </div> 

    <div class="editor-label"> 
     @Html.LabelFor(model => Model.Addressess[i].Zipcode) 
    </div> 
    <div class="editor-field"> 
     @Html.EditorFor(model => Model.Addressess[i].Zipcode) 
     @Html.ValidationMessageFor(model => Model.Addressess[i].Zipcode) 
    </div> 

    <div class="editor-label"> 
     @Html.LabelFor(model => Model.Addressess[i].City) 
    </div> 
    <div class="editor-field"> 
     @Html.EditorFor(model => Model.Addressess[i].City) 
     @Html.ValidationMessageFor(model => Model.Addressess[i].City) 
    </div> 

    <div class="editor-label"> 
     @Html.LabelFor(model => Model.Addressess[i].Country) 
    </div> 
    <div class="editor-field"> 
     @Html.EditorFor(model => Model.Addressess[i].Country) 
     @Html.ValidationMessageFor(model => Model.Addressess[i].Country) 
    </div> 

</fieldset> 

} 
    <p> 
     <input type="submit" value="Create" /> 
    </p> 
} 

的问题(我注意到在调试这样的事情时)是在r之前equest进入我的动作MVC首先运行验证器为您的收藏。所以,如果我只填写了表单中的Person,而验证Model.Person,它只是返回false(我猜是因为Address的Required字段),所以它会反弹回我的View。

我需要一些解决方法,让我决定我的集合的哪些实例要在我的操作中进行验证。

在网上搜索了很多时间之后,我还找不到任何解决方案。

我希望有人能帮助我。

PS。我是一个相当新手与Visual Studio和MVC 3所以请不要对我很难:)

+0

让我们不要把视图是理所当然的。请添加您的视图,因为视图的结构如何影响模型在发布回您的操作时的绑定方式。 – counsellorben

+0

好吧,我会在几个小时后回家,然后我会(重新)发布一切。我并不认为这种观点可能会影响模型的约束方式。 – Gyocol

+0

绑定按照惯例工作,扩展到视图中命名元素的约定。 – counsellorben

回答

2

为了验证模型的子模型返回到您的操作,您需要将TryValidateModel应用到特定的子模型,并使用包含模型前缀的重载。如果查看生成的HTML,您将看到Person字段有Person作为前缀,第一个地址字段的前缀为Addressess[0],第二个地址字段的前缀为Addressess[1]

此外,您必须在调用TryValidateModel之前清除所有模型错误(或者现有错误将导致TryValidateModel返回false)。

执行以下操作:

[HttpPost] 
public ActionResult Index(MasterModel model) 
{ 
    var reloadView = true; 

    // clear any existing errors 
    foreach (var key in ModelState.Keys) 
     ModelState[key].Errors.Clear(); 

    if (TryValidateModel(model.Person, "Person")) 
    { 
     _db.People.Add(model.Person); 
     _db.SaveChanges(); 
     reloadView = false; 

     for (var i = 0; i < model.Addressess.Count(); i++) 
     { 
      foreach (var key in ModelState.Keys) 
       ModelState[key].Errors.Clear(); 

      if (TryValidateModel(model.Addressess[i], "Addressess[" + i.ToString() + "]")) 
      { 
       **// UPDATED CODE** 
       // add Person to Address model 
       model.Addressess[i].Person = model.Person; 

       _db.Addressess.Add(model.Addressess[i]); 
       _db.SaveChanges(); 
      } 
     } 
    } 

    if (reloadView) 
    { 
     // clear and re-add all errors 
     foreach (var key in ModelState.Keys) 
      ModelState[key].Errors.Clear(); 

     TryValidateModel(model); 
     return View(model); 
    } 
    else 
    { 
     // go to some other view 
    } 
} 
+0

只是太棒了!正是我需要的。非常感谢!!!!你甚至无法想象我现在有多快乐:)。再次感谢! – Gyocol

+0

大声笑,我现在有另一个问题....当我尝试使用TryValidateModel ModelState不返回假如果该模型没有所需的字段。它只是试图保存数据库的变化和SQL限制的崩溃....任何想法? – Gyocol

+0

哎呀,这让我想起了我对你的模型做出的改变。我从模型中去除了'IValidatableObject'和'Validate'方法的继承。在您的场景中,IValidatableObject不是必需的,因为我运行了几个不同的测试,并且TryValidateModel在我测试的每个场景下都返回了正确的有效性。 – counsellorben