2

默认情况下,EF 在生成对象时使用 EntityObject。我已经修改它以使用我自己的 AbstractEntityObject 类。这样做时,我添加了 IValidatableObject,因为当您调用 context.SaveChanges() 时,我的印象是它会自动调用 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;
    }
}

由于我在 .tt 文件中更改了它,CSDCrud 继承自 AbstractTLMSEntityObject。

现在这是变得奇怪的地方。我已经对其进行了设置,以便 DBField(在父类中引用)对数据进行自我验证。在这种情况下,我已经设置了它,所以如果需要receipt_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

仅当您使用 DbContext API 而不是 ObjectContext API 时才会调用内置验证。

于 2012-10-25T19:25:09.527 回答
0

objectContext 类不会显式调用实体对象中的内置自定义验证,但程序员需要显式处理这一点。从你的结束SavingChanges事件中明确地做到这一点是最好的地方。这是怎么做到的?我在控制台应用程序中准备的快速代码片段中对此进行了描述:

课程.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


    }
}

程序.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 回答