2

デフォルトでは、EFはオブジェクトの生成時にEntityObjectを使用します。独自のAbstractEntityObjectクラスを使用するように変更しました。そうすることで、context.SaveChanges()を呼び出したときに印象に残っていたので、IValidatableObjectを追加しました。これにより、Validateが自動的に呼び出され、例外がスローされます。

これが私が持っているものです:

public abstract class AbstractEntityObject : EntityObject, IValidatableObject
{
    private readonly DBTable table;

    protected AbstractEntityObject(DBTable table)
    {
        this.table = table;
    }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        List<OITValidationResult> results = new List<OITValidationResult>();
        List<PropertyInfo> properties = new List<PropertyInfo>(GetType().GetProperties());

        foreach (DBField field in table.GetFields())
        {
            foreach (PropertyInfo prop in properties)
                if (StringUtilities.EqualsIgnoreCase(field.FieldName, prop.Name))
                {
                    results.AddRange(field.Validate(prop.GetValue(this, null)));
                    results.AddRange(AdditionalValidation(field, prop));
                    properties.Remove(prop);
                    break;
                }
        }

        return results;
    }

    public abstract List<OITValidationResult> AdditionalValidation(DBField field, PropertyInfo prop);
}

public abstract class AbstractTLMSEntityObject : AbstractEntityObject
{
    protected AbstractTLMSEntityObject(DBTable table) 
        : base(table)
    {
    }

    public override List<OITValidationResult> AdditionalValidation(DBField field, PropertyInfo prop)
    {
        List<OITValidationResult> results = new List<OITValidationResult>();

        if (!EntityState.Equals(EntityState.Unchanged))
        {
            if (StringUtilities.EqualsIgnoreCase(field.FieldName, "userid"))
                prop.SetValue(this, TLMSDB.User.UserName, null);
            else if (StringUtilities.EqualsIgnoreCase(prop.Name, "dtmod"))
                prop.SetValue(this, DateTime.Now, null);
        }

        OITValidationResult additionalResult = AdditionalValidation(field.Field);
        if (additionalResult != null)
            results.Add(additionalResult);

        return results;
    }

    /* By default there is no additional validation, subclasses should override this if they need additional validation */
    public virtual OITValidationResult AdditionalValidation(Enum field)
    {
        return null;
    }
}

次に、サブクラスがあります。これは、EFが作成するクラスと一緒に部分クラスです。

public partial class CSDCrud
{
    public enum Fields
    {
        RECEIPT_NUMBER,
        GRANT_ID,
        GRANT_FUND,
        TOTAL_ACRES
    }

    public CSDCrud() : base(CSDCrudDAO.Instance.Table)
    {
    }

    public static String GetDataPropertyName(Enum field)
    {
        return CSDCrudDAO.Instance.Table.GetField(field).FieldName;
    }
}

CSDCrudは、.ttファイルで変更したおかげでAbstractTLMSEntityObjectを継承しています。

今ここでそれは奇妙になります。DBField(親クラスで参照される)がデータの自己検証を行うように設定しました。この場合、recipient_numberが必要であり、失敗して例外をスローするように設定しました...実際には、次のようになります...

List<OITValidationResult> results = (List<OITValidationResult>)crudObject.Validate(null);
try
{
    CommonEntityManager.GetContext().CrudSet.AddObject(crudObject);
    CommonEntityManager.GetContext().SaveChanges();
    return true;
}
catch (Exception ex)
{
    return false;
}

予想どおり、結果には適切なエラーである1つの項目が含まれています...ただし、SaveChangesは例外をスローせずに、問題なく保存します...何が欠けていますか?

編集:もちろん、SavingChangesイベントを使用して独自のハンドラーを追加できますが、既存のインフラストラクチャを使用したいと考えています。

static void context_SavingChanges(object sender, EventArgs e)
    {
        foreach (ObjectStateEntry ose in context.ObjectStateManager.GetObjectStateEntries(EntityState.Modified))
        {
            List<ValidationResult> results = new List<ValidationResult>(((IValidatableObject)ose.Entity).Validate(null));
            if (results.Count > 0)
                throw new CustomException(results);
        }

        foreach (ObjectStateEntry ose in context.ObjectStateManager.GetObjectStateEntries(EntityState.Added))
        {
            List<ValidationResult> results = new List<ValidationResult>(((IValidatableObject)ose.Entity).Validate(null));
            if (results.Count > 0)
                throw new CustomException(results);
        }
    }
4

2 に答える 2

3

組み込みの検証は、ObjectContextAPIではなくDbContextAPIを使用している場合にのみ呼び出されます。

于 2012-10-25T19:25:09.527 に答える
0

エンティティオブジェクトに組み込まれているカスタム検証は、objectContextクラスによって明示的に呼び出されませんが、プログラマーはこれを明示的に処理する必要があります。エンドSavingChangesイベントから明示的にそれを行うのが最適な場所です。これがあなたがそれをする方法ですか?これは、コンソールアプリケーションで準備した簡単なコードスニペットで説明しています。

Course.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Objects.DataClasses;
using System.ComponentModel.DataAnnotations;

namespace EFCoding
{
    public partial class Course : EntityObject, IValidatableObject
    {
        List<ValidationResult> validationErrors = new List<ValidationResult>();
        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            return validationErrors;
        }

        partial void OnNameChanging(global::System.String value)
        {
            validationErrors.Clear();
            if (value.Length > 10)
            {
                ValidationResult vResult = new ValidationResult("Invalid Course Name", new string[] { "EmailID" });
                validationErrors.Add(vResult);
            }
        }

        partial void OnDisciplineChanging(global::System.String value)
        {
            validationErrors.Clear();
            if (value.Length > 10)
            {
                ValidationResult vResult = new ValidationResult("Invalid Discipline", new string[] { "EmailID" });
                validationErrors.Add(vResult);
            }
        }

    #region Factory Method

    /// <summary>
    /// Create a new Course object.
    /// </summary>
    /// <param name="id">Initial value of the Id property.</param>
    /// <param name="name">Initial value of the Name property.</param>
    /// <param name="discipline">Initial value of the Discipline property.</param>
    public static Course CreateCourse(global::System.Int32 id, global::System.String name, global::System.String discipline)
    {
        Course course = new Course();
        course.Id = id;
        course.Name = name;
        course.Discipline = discipline;
        return course;
    }

    #endregion

    #region Primitive Properties

    /// <summary>
    /// No Metadata Documentation available.
    /// </summary>
    [EdmScalarPropertyAttribute(EntityKeyProperty=true, IsNullable=false)]
    [DataMemberAttribute()]
    public global::System.Int32 Id
    {
        get
        {
            return _Id;
        }
        set
        {
            if (_Id != value)
            {
                OnIdChanging(value);
                ReportPropertyChanging("Id");
                _Id = StructuralObject.SetValidValue(value);
                ReportPropertyChanged("Id");
                OnIdChanged();
            }
        }
    }
    private global::System.Int32 _Id;
    partial void OnIdChanging(global::System.Int32 value);
    partial void OnIdChanged();

    /// <summary>
    /// No Metadata Documentation available.
    /// </summary>
    [EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
    [DataMemberAttribute()]
    public global::System.String Name
    {
        get
        {
            return _Name;
        }
        set
        {
            OnNameChanging(value);
            ReportPropertyChanging("Name");
            _Name = StructuralObject.SetValidValue(value, false);
            ReportPropertyChanged("Name");
            OnNameChanged();
        }
    }
    private global::System.String _Name;
    partial void OnNameChanging(global::System.String value);
    partial void OnNameChanged();

    /// <summary>
    /// No Metadata Documentation available.
    /// </summary>
    [EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
    [DataMemberAttribute()]
    public global::System.String Discipline
    {
        get
        {
            return _Discipline;
        }
        set
        {
            OnDisciplineChanging(value);
            ReportPropertyChanging("Discipline");
            _Discipline = StructuralObject.SetValidValue(value, false);
            ReportPropertyChanged("Discipline");
            OnDisciplineChanged();
        }
    }
    private global::System.String _Discipline;
    partial void OnDisciplineChanging(global::System.String value);
    partial void OnDisciplineChanged();

    #endregion


    }
}

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.DataAnnotations;
using System.Data.Objects;
using System.Data;

namespace EFCoding
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var efContext = new EfTestEntities1())
            {

                efContext.SavingChanges += new EventHandler(efContext_SavingChanges);
                var course = new Course { Id = 2, Name = "Very long course name which will result in exception", Discipline = "Very long discipline name which will result in error at run time" };
                efContext.Courses.AddObject(course);
                efContext.SaveChanges();
            }
        }

        static void efContext_SavingChanges(object sender, EventArgs e)
        {
            ObjectContext objectContext = sender as ObjectContext;
            IEnumerable<Object> entities = objectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified).Select(x => x.Entity);
            foreach (var item in entities)
            {
                var current = item as Course;
                if (current != null)
                {
                    var validationsErrors = current.Validate(new ValidationContext(current,null,null));
                    if (validationsErrors.Count() > 0)
                    {
                        throw new InvalidOperationException("Model has validation errors");
                    }
                }
            }
        }
    }
}
于 2016-05-18T00:17:21.247 に答える