LLBL Gen 3.x 源代码追踪与解析 验证Validation的原理和流程
先看应用程序如何应用验证。以SalesOrderHeaderEntity为例子。
常见的三种验证:
1)保存之前的验证,重写ValidateEntityBeforeSave
2) 删除前的验证,重写ValidateEntityBeforeDelete
3) 属性获取值之后的验证,重写ValidateFieldValue
先讲解一个基本的模式,基类中的设计virtual方法,派生中中override,我们在运行时,会调用实际类型的方法
public class A
{
public virtual Do() { }
}
public class B: A
{
public override Do() { }
}
当以这种方法调用时
A obj=new B():
obj.Do();
它会根据obj的实际类型,调用对应的方法
验证代码的书写
[Serializable]
public partial class SalesOrderHeaderValidator : ValidatorBase
{
// __LLBLGENPRO_USER_CODE_REGION_START ValidationCode
删除采购单前的验证,比如采购单还在被合同contact引用,则不允许删除
public override void ValidateEntityBeforeDelete(IEntityCore involvedEntity)
{
base.ValidateEntityBeforeDelete(involvedEntity);
SalesOrderHeaderEntity salesOrder = (SalesOrderHeaderEntity)involvedEntity;
if (salesOrder.TotalDue != 0)
throw new Exception("Total due zero not allow for this period");
}
保存采购单前的验证,常常是验证必须输入值的字段
public override void ValidateEntityBeforeSave(IEntityCore involvedEntity)
{
base.ValidateEntityBeforeSave(involvedEntity);
SalesOrderHeaderEntity salesOrder = (SalesOrderHeaderEntity)involvedEntity;
if(salesOrder.TaxAmt>1000)
throw new Exception("unable to deal with tax more than 1000");
}
采购单的属性值发生改变时,应用此处的验证,比如,当获取截止日期后,要验证它不能小于当前日期
public override bool ValidateFieldValue(IEntityCore involvedEntity, int fieldIndex, object value)
{
bool result = base.ValidateFieldValue(involvedEntity, fieldIndex, value);
if (!result)
return false;
SalesOrderHeaderEntity salesOrder = (SalesOrderHeaderEntity)involvedEntity;
switch ((SalesOrderHeaderFieldIndex)fieldIndex)
{
case SalesOrderHeaderFieldIndex.DueDate:
return ValidateDueDate(salesOrder, (DateTime)value);
}
return true;
}
private bool ValidateDueDate(SalesOrderHeaderEntity salesOrder, DateTime value)
{
if(value.CompareTo(DateTime.Now) < 0)
throw new Exception("Due date cannot be less than today");
return true;
}
}
挂接到验证代码到实体中
重写OnInitialized方法,给Validator 属性指定验证器
protected override void OnInitialized()
{
base.OnInitialized();
//Assign validator
this.Validator =new SalesOrderHeaderValidator();
}
追踪删除采购单的堆栈
先设计一个删除的采购单的测试方法
[TestMethod]
public void TestDeleteSalesOrderHeader()
{
DataAccessAdapter adapter = new DataAccessAdapter(ConnectionString);
SalesOrderHeaderEntity salesOrder = new SalesOrderHeaderEntity(43659);
adapter.DeleteEntity(salesOrder);
}
进入DataAccessAdapterBase的方法
public bool DeleteEntity(IEntity2 entityToDelete)
{
return DeleteEntity(entityToDelete, null);
}
调用它的重载overload方法
public virtual bool DeleteEntity(IEntity2 entityToDelete, IPredicateExpression deleteRestriction)
{
EntityBase2 entityToDeleteAsEntityBase2 = (EntityBase2)entityToDelete;
entityToDeleteAsEntityBase2.CallValidateEntityBeforeDelete();
}
进入EntityBase2的CallValidateEntityBeforeDelete
internal void CallValidateEntityBeforeDelete()
{
OnValidateEntityBeforeDelete();
}
继续进入OnValidateEntityBeforeDelete方法
protected virtual void OnValidateEntityBeforeDelete()
{
if( _validator != null )
{
_validator.ValidateEntityBeforeDelete( this );
}
}
至此就进入到了我在文章开头写的SalesOrderHeaderValidator的ValidateEntityBeforeDelete方法
再来看一下ValidatorBase 中的虚拟方法ValidateEntityBeforeDelete
[Serializable]
public abstract class ValidatorBase : IValidator
{
public virtual void ValidateEntityBeforeDelete( IEntityCore involvedEntity )
{
// nop
}
}
验证属性值
再来看属性设置时的验证,这种验证方法可以验证程序对采购单的任何属性的复制行为。比如,业务规则是,任何时间,采购单的截止日期都不能小于输入采购单的当天,代码如下,
SalesOrderHeaderEntity salesOrder = new SalesOrderHeaderEntity(2068);
salesOrder.DueDate = DateTime.Now.AddDays(-1); //这里设置DueDate 的值为昨天,违反了业务规则
来追踪它的堆栈,进入DueDate属性的set方法
public virtual System.DateTime DueDate
{
set { SetValue((int)SalesOrderHeaderFieldIndex.DueDate, value); }
}
进入EntityBase2的SetValue方法
protected bool SetValue(int fieldIndex, object value)
{
return SetValue(fieldIndex, value, true);
}
同名的重载方法
protected bool SetValue(int fieldIndex, object value, bool performDesyncForFKFields)
{
// set value is not the same as the value to set, proceed
if(ValidateValue(fieldToSet, ref valueToSet, fieldIndex))
进入ValidateValue方法
private bool ValidateValue(IFieldInfo fieldToValidate, ref object value, int fieldIndex)
{
// perform custom validation.
validationResult = (OnValidateFieldValue(fieldIndex, value));
}
流程进入OnValidateFieldValue方法
protected virtual bool OnValidateFieldValue( int fieldIndex, object value )
{
bool returnValue = true;
if( _validator != null )
{
returnValue = _validator.ValidateFieldValue(this, fieldIndex, value );
}
return returnValue;
}
请注意看这一句returnValue = _validator.ValidateFieldValue(this, fieldIndex, value ),它会进入我在开头重写的ValidateFieldValue的方法里面,最后就是进入自定义的方法ValidateDueDate
这就是验证的完整堆栈流程。