1

私はMVCとEFの世界にかなり慣れていないので、自分でかなりの方法でやって来ましたが、オンラインで見つけることができなかったことの1つは、人々が「削除しない」条件を検証する方法です。

DbContextT4テンプレートで生成されたEF4.1データベースファーストのPOCOクラスを使用しています。部分的なクラスファイルでは、標準のMetaData属性タイプの検証を超えるビジネスルールの変更時に呼び出される「IValidatableObject」インターフェイスですべてのクラスをすでに装飾しています。

私が今必要としているのは、削除がOKかどうかをチェックするために同じメカニズムを介して機能する(したがって、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;
    }

    ....
}

私は正しい方向に進んでいますか?もっと良い方法はありますか?

ありがとう、
CList

編集---Pawelによって提案された1インターフェース方式の要約(下記)

以下に示す1つのインターフェースの方法と、上記の私の方法は、あなたがそれをどのようにやりたいかという点で、チョコレート対バニラの議論のほんの少しだと思います。多数の更新/削除のパフォーマンスはほぼ同じである必要があります。削除の検証を、検証済みのすべてのクラスに適用されない別個のインターフェイスにしたい場合がありますが、すべての検証を1か所にまとめたい場合はここにあります...

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コードを1つの場所に配置するだけで、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())
        {
            ....
4

1 に答える 1

1

削除されたエンティティ専用に別のインターフェイスが必要な理由はよくわかりません。base.ValidateEntity()メソッドに渡すアイテムディクショナリを使用して、エンティティの状態(またはEntityEntryオブジェクト、またはコンテキスト)をIValidatableObject.Validate()メソッドに渡すことができます。このブログ投稿http://blogs.msdn.com/b/adonet/archive/2011/05/27/ef-4-1-validation.aspxの「CustomValidationSample:Uniqness」セクションをご覧ください。このようにして、1つのインターフェイス(IValidatableObject)を使用してすべてを実行できます。それに加えて、デフォルトでは、EFは追加および変更されたエンティティのみを検証します。Deleted状態のエンティティを検証する場合は、DbContext.ShouldValidateEntity()メソッドを次のようにオーバーライドする必要があります。

protected override bool ShouldValidateEntity(DbEntityEntry entityEntry)
{
    return entityEntry.Sate == EntityState.Deleted || 
               base.ShouldValidateEntity(entityEntry);
}
于 2012-09-14T18:14:57.050 に答える