我正在使用EFCodeFirst CTP5(虽然这应该没什么区别)和ASP.NET MVC 3.我创建了以下实体:
public class Company
{
public int CompanyID { get; set; }
public int SubdomainID { get; set; }
public virtual Subdomain Subdomain { get; set; }
}
public class Subdomain : IValidatableObject
{
public int SubdomainID { get; set; }
public virtual ICollection<SubdomainActivity> Activities { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
int activitySum = Activities.Sum(x => x.Value);
if (activitySum != 100)
{
yield return new ValidationResult(string.Format("The Activity percentages must add up to 100. Current sum is {0}", activitySum), new[] { "Activities" });
}
}
}
public class SubdomainActivity
{
public int ActivityID { get; set; }
public int Value { get; set; }
}
请注意,Company
有Subdomain
而Subdomain
有ICollection<SubdomainActivity>
。
我有Company
和Subdomain
的控制器。在SubdomainController
我在UpdateModel()
的实例上调用TryUpdateModel()
(或Subdomain
)时,我得到了我想要的结果。 Subdomain
活动经过验证,值总计为100.
在我CompanyController
的{{1}}实例UpdateModel()
上,Company
确认Subdomain.Activities
加起来也是100,我不想要。用户甚至无法编辑Subdomain.Activites
编辑视图中的Company
,因此告诉他们Subdomain.Activities
出错是没有意义的。
我希望能够在validationContext.Items IDictionary中添加一个项目,以便我可以根据上下文或类似的东西进行有条件的验证,但是如果不写我的话,我就无法弄清楚如何做到这一点拥有自己的IModelBinder(我想我可以做,但看起来有点过分)。最后,我在CompanyController
中提出了这种解决方法,但我确信有一种正确的方法来解决这个问题(这包含在try
catch
)
var d = this.companyRepository.GetById(id);
bool good = TryUpdateModel(d);
if (!good)
{
if (ModelState.ContainsKey("Subdomain.Activities"))
ModelState.Remove("Subdomain.Activities");
if (!ModelState.IsValid)
throw new InvalidOperationException(string.Format("The model of type '{0}' could not be updated.", typeof(Company).FullName));
}
this.companyRepository.Save();
作为一个有趣的附注,如果我不检查模型是否有效并抛出错误,那么companyRepository.Save()工作正常。换句话说,EFCodeFirst似乎不会在子域上调用Validate,但MVC UpdateModel会这样做。
任何人都可以用更好/正确/推荐的方式帮助我解决这个问题吗?
答案 0 :(得分:0)
我找到了一种更优雅地处理这个问题的方法。我没有在IValidatableObject
上实现Subdomain
,而是在Subdomain的Activities属性上使用[CustomValidation]
属性。在我的问题中验证Company
实例时没有调用此方法,我仍然可以对活动进行专门的验证。希望有一天这会帮助某个人。
public class Subdomain
{
public int SubdomainID { get; set; }
[CustomValidation(typeof(Subdomain), "ValidateActivities")]
public virtual ICollection<SubdomainActivity> Activities { get; set; }
public static ValidationResult ValidateActivities(ICollection<SubdomainActivity> activities)
{
if (activities.Count > 0)
{
int activitySum = activities.Sum(x => x.Value);
if (activitySum != 100)
{
return new ValidationResult(string.Format("The Activity percentages must add up to 100. Current sum is {0}", activitySum), new[] { "Activities" });
}
}
return ValidationResult.Success;
}
}
答案 1 :(得分:0)
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
int activitySum = Activities.Sum(x => x.Value);
if (activitySum != 100)
{
yield return new ValidationResult(string.Format("The Activity percentages must add up to 100. Current sum is {0}", activitySum), new[] { "Activities" });
}
}
如下修改Validate()方法呢?
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
int activitySum = Activities.Sum(x => x.Value);
if (Activities.Count != 0 && activitySum != 100)
{
yield return new ValidationResult(string.Format("The Activity percentages must add up to 100. Current sum is {0}", activitySum), new[] { "Activities" });
}
}