在某些情况下应该应用不同的验证逻辑时,如何实现实体框架实体的验证?
例如,如果用户是管理员,则以一种方式验证实体,否则以不同方式验证。
答案 0 :(得分:2)
我将验证属性放在特定于上下文的专用编辑模型上。
该实体只有适用于所有实体的验证。
答案 1 :(得分:2)
在我开始讨论如何使用VAB执行此操作之前,请允许我说您必须真正考虑验证规则。虽然区分角色之间的验证是可能的,但它确实意味着一个角色中的用户保存的对象对另一个用户无效。这意味着某个角色的用户可能需要先更改该对象才能保存该对象。当同一用户被提升为另一个角色时,也会发生这种情况。如果您确定要这样做,请继续阅读。
对于Enterprise Library的Validation Application Block(VAB)来说,这似乎是一个很好的工作,因为它允许验证这些复杂的场景。如果要执行此操作,请忘记基于属性的验证;它根本行不通。您需要基于配置的验证才能实现此目的。
使用VAB可以执行的操作是使用包含实际验证的配置文件。它取决于实际验证规则应该是什么,但您可以做的是创建一个始终适用于您域中每个对象的基本配置。接下来创建一个或多个包含仅扩展验证的配置。例如,假设您有一个validation_base.config
文件,一个validation_manager.config
和一个validation_admin.config
文件。
您可以做的是根据用户的角色将这些验证合并在一起。在此示例中查找基于配置文件创建三个配置源的示例:
var base = new FileConfigurationSource("validation_base.config");
var mngr = new FileConfigurationSource("validation_manager.config");
var admn = new FileConfigurationSource("validation_admin.config");
现在您必须将这些文件合并到(至少)两个配置中。一个包含base + manager,另一个包含base + admin规则。虽然合并不是开箱即用的,但this article会告诉您如何进行合并。使用该文章中的代码时,您将能够执行此操作:
var managerValidations =
new ValidationConfigurationSourceCombiner(base, mngr);
var adminValidations =
new ValidationConfigurationSourceCombiner(base, admn);
您需要做的最后一件事是将这些验证包装在一个类中,该类根据用户的角色返回正确的集合。你可以这样:
public class RoleConfigurationSource : IConfigurationSource
{
private IConfigurationSource base;
private IConfigurationSource managerValidations;
private IConfigurationSource adminValidations;
public RoleConfigurationSource()
{
this.base = new FileConfigurationSource("validation_base.config");
var mngr = new FileConfigurationSource("validation_manager.config");
var admn = new FileConfigurationSource("validation_admin.config");
managerValidations =
new ValidationConfigurationSourceCombiner(base, mngr);
adminValidations =
new ValidationConfigurationSourceCombiner(base, admn);
}
public ConfigurationSection GetSection(string sectionName)
{
if (sectionName == ValidationSettings.SectionName)
{
if (Roles.UserIsInRole("admin"))
{
return this.adminValidations;
}
else
{
return this.managerValidations;
}
}
return null;
}
#region IConfigurationSource Members
// Rest of the IConfigurationSource members left out.
// Just implement them by throwing an exception from
// their bodies; they are not used.
#endregion
}
现在可以创建一次RoleConfigurationSource
,您可以在验证对象时提供它,如下所示:
static readonly IConfigurationSource validationConfiguration =
new RoleConfigurationSource();
Validator customerValidator =
ValidationFactory.CreateValidator<Customer>(validationConfiguration);
ValidationResults results = customerValidator.Validate(customer);
if (!results.IsValid)
{
throw new InvalidOperationException(results[0].Message);
}
请注意,验证应用程序块不是一个简单的框架。学习它需要一些时间。当您的应用程序足够大时,您的特定要求将证明其使用是合理的。如果您选择VAB,请首先阅读“Hands-On Labs”文档。如果您遇到问题,请回到SO; - )
祝你好运。答案 2 :(得分:1)
直到我听到更明智的想法,我才这样做:
public partial class MyObjectContext
{
ValidationContext ValidationContext { get; set; }
partial void OnContextCreated()
{
SavingChanges += new EventHandler(EntitySavingChanges);
}
private void EntitySavingChanges(object sender, EventArgs e)
{
ObjectStateManager
.GetObjectStateEntries(EntityState.Added | EntityState.Modified | EntityState.Deleted)
.Where(entry => entry.Entity is IValidatable).ToList().ForEach(entry =>
{
var entity = entry.Entity as IValidatable;
entity.Validate(entry, ValidationContext);
});
}
}
interface IValidatable
{
void Validate(ObjectStateEntry entry, ValidationContext context);
}
public enum ValidationContext
{
Admin,
SomeOtherContext
}
public partial class MyEntity : IValidatable
{
public ValidationContext ValidationContext { get; set; }
public void Validate(ObjectStateEntry entry, ValidationContext context)
{
// this validation doesn't apply to admins
if (context != ValidationContext.Admin)
{
// validation logic here
}
}
}