【发布时间】:2012-10-25 16:36:12
【问题描述】:
默认情况下,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);
}
}
【问题讨论】:
-
你在使用 ObjectContext 吗?仅当您使用 DbContext 时才会调用验证。糟糕,我想我需要重新阅读您的问题
-
好的。我重新阅读 - 我被最后一个代码片段误导了,这是解决您的问题的方法。验证仅在使用 DbContext 时有效
-
@Pawel 那么如果实体框架不打算利用它来进行模型验证,那么实现 IValidatableObject 接口的实体类的全部目的是什么?那么在实体被提交到数据库之前谁应该调用它呢?每当我将对象添加到 objectContext 时,我都可以在我的实体对象的属性更改事件中创建 List
。如果有人愿意,这个列表可以通过 Validate 方法返回。 -
嘿@Pawel 很抱歉打扰你。我刚刚发现它应该由程序员通过 objectContext 的 objectStateManager 属性获取插入的实体来显式调用。
标签: .net entity-framework c#-4.0