当属性验证依赖于另一个属性值时,如何使用元数据验证实体框架4模型?
本文关键字:属性 验证 实体 元数据 框架 模型 何使用 另一个 依赖于 | 更新日期: 2023-09-27 18:02:23
我有一个实体框架模型,我试图添加验证,但我发现我自己在这里有点catch 22。
我在一个单独的文件中有一个与实体生成模型相关的部分类,看起来像这样…
[MetadataType(typeof(cmsNodeMetadata))]
public partial class cmsNode : IDataErrorInfo
{
... Code ....
#region IDataErrorInfo
private readonly Dictionary<string, string> _errors = new Dictionary<string, string>();
private readonly Entities _db = new Entities();
public string this[string columnName]
{
get
{
if (_errors.ContainsKey(columnName))
return _errors[columnName];
return string.Empty;
}
}
public string Error { get; private set; }
partial void OnNameChanging(string value)
{
var valueIsUnique = (from n in _db.cmsNodes
where n.ParentId == ParentId
&& n.Name.Trim().ToLower() == value.Trim().ToLower()
select n.Name).Count() == 0;
if (!valueIsUnique)
{
_errors.Add("Name", "The name must be unique");
}
}
#endregion
}
…我在一个单独的类中添加了验证,效果很好。
public class cmsNodeMetadata
{
[StringLength(150), Required]
[Display(Name = "Name")]
public string Name;
}
我使用MVC 3和我的控制器,使用这个类看起来像这样…
[HttpPost]
public ActionResult Edit(cmsNode cmsnode)
{
if (ModelState.IsValid)
{
var obj = _db.cmsNodes.Single(c => c.Id == cmsnode.Id);
obj.Name = cmsnode.Name;
obj.Alias = cmsnode.Name.Slugify(150);
_db.SaveChanges();
return Content(Boolean.TrueString);
}
return Content("Please review your form");
}
使用这个类的视图是这样的…
@model Project.com.Admin.Models.cmsNode
@using (Ajax.BeginForm("Create", "Node", null, new AjaxOptions
{
UpdateTargetId = "create-message",
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST",
OnSuccess = "createSuccess"
}, new { @id = "createNodeForm" }))
{
@Html.ValidationSummary(true)
<div id="create-message" class="error invisible"></div>
<fieldset>
<legend>Create New Navigation Tree Node</legend>
<div class="editor-label">
@Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Name)
@Html.ValidationMessageFor(model => model.Name)
</div>
@Html.HiddenFor(model => model.ParentId)
@Html.HiddenFor(model => model.Alias)
</fieldset>
}
好的,这就是问题所在。我需要向这个(cmsNode)类添加一些自定义验证,以检查该名称是否已被具有相同ParentId的任何其他节点所采用。
为了做到这一点,我需要得到一个实例成员名为ParentId的句柄。不幸的是,我不知道如何从cmsNodeMetadata类获得我正在验证的实例的句柄。
所以我试图改变我的方法通过覆盖onChanging方法的名称属性在我的cmsNode类和添加验证,但这引起了另一个问题。虽然我能够使用验证的重写方法检查name属性,但当name从视图返回未设置时,我会得到异常,因为我的实体模型不为name属性排除空值,而且我无法捕获它,因为视图的内容在我的控制器的输入参数中被转换为模型类型。
然后我尝试使用两者,但MetadatatType和onChanging验证方法在一起,但onChanging方法被忽略。
我意识到我可以用下列方法解决这个问题:
- 我可以将控制器的返回类型更改为FormCollection collection,一个dto对象,或者直接定义输入属性,然后在我检查空值后在控制器中使用并创建对象。
我只是想知道我错过了什么?是否有一种方法来验证属性并使用ValidationAttributes检查重复的名称?我能阻止null从我的视图返回吗?为什么在实体框架的onChanging方法有一个取消选项,以防止成员被设置,如果验证不工作?谢谢你的帮助!
跨实体验证不是实体本身的一部分,因为它不是实体的责任。因此,您不应该期望该实体或放置在该实体上的任何验证器会执行此验证。实体不应该做这种验证的另一个原因是,它需要上下文来进行查询,而实体(POCO)不应该依赖于上下文。
谁负责验证?根据应用程序的体系结构,一旦实体本身有效,将在IsValid
块中调用单独的方法。此方法将使用EF并查询是否存在相同的名称。如果你接近域驱动设计,验证应该在父级,这将验证它的子级没有相同的名字(这意味着它将加载子级)。