默认情况下,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;
}
}
CSDCrud继承自AbstractTLMSEntityObject,这要归功于我在.tt文件中的更改。
现在这里变得奇怪了。我已将其设置为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);
}
}
答案 0 :(得分:2)
只有在使用DbContext API而不是ObjectContext API时才会调用内置验证。
答案 1 :(得分: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");
}
}
}
}
}
}