首先,抱歉我的英语。不是我的自然语言。
我有一个名为Category
的类,如下面的代码所示。请注意,在此代码中我还有一个Category
属性,我可以在其中引用父类别。它只是在类中声明的同一个类。像Inception一样。因此,这个父类别对象具有“声明他的类”的相同属性。
属性Name
是必需的。记住这个属性。
public class Category
{
public int? Id{ get; set; }
[DisplayName("Father Category")] //NOT REQUIRED
public Category Father { get; set; }
[DisplayName("Category")]
[Required(ErrorMessage = "Name is required")] //REMEMBER THIS REQUIRED PROPERTY!!
public string Name { get; set; }
[DisplayName("Status")]
public bool Status { get; set; }
[DisplayName("Description")]
public string Description { get; set; }
}
那是我的班级。
所以,在类别视图中,我可以这样做:
注意:CompleteEditorFor
和CompleteDropDownListFor
是扩展方法,在每个字段中添加一些额外的html,仅用于调整布局。
@using (Html.BeginForm(null, null, FormMethod.Post))
{
@Html.CompleteEditorFor(x => x.Name)
@Html.CompleteEditorFor(x => x.Description)
@Html.CompleteEditorFor(x => x.Status)
@Html.CompleteDropDownListFor(x => x.Father.Id, ViewData["Categories"], "Id", "Name", "Select...")
@Html.SubmitButton()
}
上面的代码运行得很好。
现在出现了问题:
当我点击“保存”按钮时,它会生成HttpPost
,这就是Action
:
(下面的代码有一些修改过的消息字符串和扩展方法。)
(CategoriesBLL
是从数据库中获取类别的类。)
[HttpPost]
public ActionResult New(Category item)
{
ViewData.Add("Categories", CategoriesBLL.select());
try
{
if (ModelState.IsValid)//PROBLEM IS HERE!!!!!!!!!
{
if (CategoryBLL.insert(item) != 0)
{
ViewData.AddSuccess("Some Success Message");
return View(new Category());
}
else
{
ModelState.AddError("Some error message");
return View(item);
}
}
else
{
ModelState.AddError("Some SERIOUS error message");
return View(item);
}
}
catch (Exception ex)
{
ModelState.AddError("Some EVEN MORE SERIOUS message");
return View(item);
}
}
问题出在if (ModelState.IsValid)
行。
为什么?
因为我的Category
类有一个名为Name
的必需属性。我不需要这个属性来做我正在做的事情,我只需要Id
属性的Father
。我可以在View:
Id
@Html.CompleteDropDownListFor(x => x.Father.Id, ViewData["Categories"], "Id", "Name", "Select...")
这很有效。
但是Name
属性是null
,并且是必需的,但它仅在我通知Child类时才需要。不是父班。
我甚至不知道如何在Google或StackOverflow上搜索它......
任何人都可以帮助我吗?
答案 0 :(得分:2)
您可能需要考虑在模型上创建类IValidatableObject接口而不是属性装饰器。如果你真的想使用一个属性装饰器,那么你可能会对自定义装置进行修改。
答案 1 :(得分:2)
您需要使用View Models。您的视图模型应包含视图中所需的所有字段,减去父属性。然后在您的控制器中,您需要将视图模型映射到模型。您可以使用Automapper轻松完成此操作。 (但是,不推荐从视图到域模型的直接映射,但稍后会对其进行排序)
我知道,起初这可能看起来像拖累,但相信我。您的视图与您的域模型不同。接下来你会知道,你需要在视图上添加某种下拉菜单,以及在域模型中没有的其他额外复选框。此外,如果您使用视图模型,您的安全性将得到改善。如果有兴趣,我会告诉你一些关于它的信息。
答案 2 :(得分:1)
public class Category : IValidatableObject
{
public int? Id{ get; set; }
[DisplayName("Father Category")] //NOT REQUIRED
public Category Father { get; set; }
[DisplayName("Category")]
[Required(ErrorMessage = "Name is required")] //REMEMBER THIS REQUIRED PROPERTY!!
public string Name { get; set; }
[DisplayName("Status")]
public bool Status { get; set; }
[DisplayName("Description")]
public string Description { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var results = new List<ValidationResult>();
if (this.Enable)
{
Validator.TryValidateProperty(this.Name ,
new ValidationContext(this, null, null) { MemberName = "Name" },
results);
Validator.TryValidateProperty(this.Status,
new ValidationContext(this, null, null) { MemberName = "Status" },
results);
}
return results;
}
}
public void Validate()
{
var toValidate = new Category()
{
Name = "Just a name",
Status = true
};
bool validateAllProperties = false;
var results = new List<ValidationResult>();
bool isValid = Validator.TryValidateObject(
toValidate,
new ValidationContext(toValidate, null, null),
results,
validateAllProperties);
}
答案 3 :(得分:1)
OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES
或
ModelState.Remove("PropertyNameInModel");