实体框架上下文验证

时间:2010-09-20 16:38:48

标签: c# .net entity-framework validation

在某些情况下应该应用不同的验证逻辑时,如何实现实体框架实体的验证?

例如,如果用户是管理员,则以一种方式验证实体,否则以不同方式验证。

3 个答案:

答案 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
        }
    }  
}