EF,POCO,DbContext和验证删除

时间:2012-09-13 12:29:45

标签: asp.net-mvc-3 entity-framework-4 dbcontext

我对MVC和EF世界相当新,我自己也有很多方法,但我在网上找不到的一件事就是人们如何验证“不要删除”条件。

我正在使用使用DbContext T4模板生成的EF4.1数据库优先POCO类。在我的部分类文件中,我已经使用“IValidatableObject”接口修饰了我的所有类,该接口调用了超出标准MetaData属性类型验证的业务规则的更改。

我现在需要的是通过相同的机制(因此,对UI和控制器透明)进行验证,以检查删除是否正常。我的想法是创建一个这样的界面:

public interface IDeletionValidation
{
    DbEntityValidationResult ValidateDeletion(DbEntityValidationResult validationResults);
}

...然后在DbContext中的ValidateEntity覆盖中执行此操作...

public partial class MyEntityContext
{
   protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<object, object> items)
    {
        DbEntityValidationResult val = base.ValidateEntity(entityEntry, items);
        if (entityEntry.State == EntityState.Deleted)
        {
            IDeletionValidation delValidationEntity = entityEntry.Entity as IDeletionValidation;
            if (delValidationEntity != null)
                val = delValidationEntity.ValidateDeletion(val);
        }
        return val;
    }

...然后我可以在那些需要完成验证的类上实现IDeletionValidation接口,然后才能安全删除它们。

ValidateDeletion代码的示例(不工作,请参阅注释中的警告)将是......

public partial class SalesOrder : IDeletionValidation, IValidatableObject  
{
    public DbEntityValidationResult ValidateDeletion(DbEntityValidationResult validations)
    {
        // A paid SalesOrder cannot be deleted, only voided
        // NOTE: this code won't work, it's coming from my head and note from the actual source, I forget
        // what class I'd need to add to the DbEntityValidationResult collection for this type of validation! 
        if (PaidAmount != 0) 
             validations.Add(new ValidationResult("A paid SalesOrder cannot be deleted, only voided"));
        return validations;
    }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        List<ValidationResult> validations = new List<ValidationResult>();

        // Verify that the exempt reason is filled in if the sales tax flag is blank
        if (!IsTaxable && string.IsNullOrEmpty(TaxExemptReason))
            validations.Add(new ValidationResult("The Tax Exempt Reason cannot be blank for non-taxable orders"));

        return validations;
    }

    ....
}

我是否在正确的轨道上?还有更好的方法吗?

谢谢,
分栏列表

编辑--- Pawel(下文)

提出的单接口方法摘要

我认为下面介绍的单接口方式和我上面的方式在你想要的方式上有点巧克力与普通话的争论。对于大量更新/删除,性能应该大致相同,并且您可能希望让您的删除验证成为不适用于所有已验证类的单独接口,但如果您需要你在一个地方的所有验证都是......

修改您的DBContext

protected override bool ShouldValidateEntity(DbEntityEntry entityEntry)
{
    return entityEntry.Sate == EntityState.Deleted || 
           base.ShouldValidateEntity(entityEntry);
}

protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<object, object> items)
{
    var myItems = new Dictionary<object, object>();
    myItems.Add("IsDelete", (entityEntry.State == EntityState.Deleted));

    // You could also pass the whole context to the validation routines if you need to, which might be helpful if the 
    // validations need to do additional lookups on other DbSets
    // myItems.Add("Context", this);

    return base.ValidateEntity(entityEntry, myItems);
}

将删除验证放入实体的验证

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        List<ValidationResult> validations = new List<ValidationResult>();

        bool isDelete = validationContext.Items.ContainsKey("IsDelete")
                                ? (bool)validationContext.Items["IsDelete"] 
                                : false;
        if (isDelete)
        {
            if (PaidAmount != 0)
                validations.Add(new ValidationResult("You cannot delete a paid Sales Order Line", new string[] { "PaidAmount" }));
            return validations;
        }

        // Update / Add validations!!
        // Verify that the exempt reason is filled in if the sales tax flag is blank
        if (!IsTaxable && string.IsNullOrEmpty(TaxExemptReason))
            validations.Add(new ValidationResult("The Tax Exempt Reason cannot be blank for non-taxable orders"));

        return validations;
    }

...为了简洁起见,只将所有check-if-delete代码放在一个地方,你甚至可以在ValidationContext类上创建一个扩展方法(如果你是那种东西)像这样...

public static class MyExtensions
{
    public static bool IsDelete(this System.ComponentModel.DataAnnotations.ValidationContext validationContext)
    {
        return validationContext.Items.ContainsKey("IsDelete")
                                ? (bool)validationContext.Items["IsDelete"] 
                                : false;
    }
}

...这为我们的验证码提供了这个......

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        List<ValidationResult> validations = new List<ValidationResult>();

        if (validationContext.IsDelete())
        {
            ....

1 个答案:

答案 0 :(得分:1)

我不确定为什么你只需要一个单独的界面来删除实体。您可以使用传递给base.ValidateEntity()方法的items字典将实体状态(或EntityEntry对象或上下文)传递给IValidatableObject.Validate()方法。请查看此博客文章http://blogs.msdn.com/b/adonet/archive/2011/05/27/ef-4-1-validation.aspx中的“自定义验证示例:Uniqness”部分。这样你就可以只使用一个接口--IValidatableObject来完成所有事情。 除此之外 - 默认情况下,EF仅验证添加和修改的实体。如果要验证处于“已删除”状态的实体,则需要使用以下内容覆盖DbContext.ShouldValidateEntity()方法:

protected override bool ShouldValidateEntity(DbEntityEntry entityEntry)
{
    return entityEntry.Sate == EntityState.Deleted || 
               base.ShouldValidateEntity(entityEntry);
}