asp.net mvc上使用EF(实体框架)中的Model Validation与UI自动绑定感觉还可以
最近碰到要做c/s结构系统,winform并没有直接支持,自己尝试实现一个
第一步
根据winform ui control上验证方式和数据绑定方式
EF上entity object实现IDataErrorInfo接口就可以了
第二步
利用DataAnnotation完成entity object上验证接口
DataAnnotation是.net内置的验证框架(其他验证框架有Castle Validator ,EntLib Validation Library)
使用DataAnnotation主要是为了减少第3方引用不方便,而且EF声明式验证需要结合MetaDataType关联验证类
.net内置的DataAnnotation中也有了
第三步
结合IDataErrorInfo和验证接口就可以达到的Model Validation与UI自动绑定的效果
第四步
EF设计器上自定义代码产生,他是利用T4来编写的,这样不用为每个entity object手动写patial类
系统最后采用的是EF+CAB(Composite UI Application Block)
因为采用Model Validation与UI自动绑定所以CAB这个框架下业务模块当然采用了MVC模式方式
验证部分实现代码如下:
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.ComponentModel.DataAnnotations;
using System.Reflection;
using System.Data.Objects.DataClasses;
namespace ChildrenModel
{
class EntityObjectValidationProvider : IValidationProvider
{
private PropertyInfo[] properties;
private object objectInstance;
private Dictionary<PropertyInfo, string> failedProperties = new Dictionary<PropertyInfo, string>();
public EntityObjectValidationProvider(object objectInstance)
{
this.objectInstance = objectInstance;
}
#region IValidationProvider Members
public virtual bool IsValid()
{
Type thisClass = objectInstance.GetType();
Type metaType = typeof(MetadataTypeAttribute);
bool isDefined = Attribute.IsDefined(thisClass, metaType);
if (!isDefined)
{
return true;
}
Attribute attribute = Attribute.GetCustomAttribute(thisClass, metaType);
MetadataTypeAttribute metaAttribute = attribute as MetadataTypeAttribute;
if (metaAttribute == null)
{
return true;
}
Type metaModelType = metaAttribute.MetadataClassType;
properties = GetProperties(metaModelType);
if (properties != null)
{
foreach (var prop in properties)
{
object[] objs = prop.GetCustomAttributes(typeof(ValidationAttribute), true);
foreach (var attrib in objs)
{
ValidationAttribute vAttrib = attrib as ValidationAttribute;
if (vAttrib!=null)
{
object[] runWhenObjs =prop.GetCustomAttributes(typeof(RunWhenAttribute), true);
RunWhen runWhen = RunWhen.Everytime;
foreach (var runWhenAttrib in runWhenObjs)
{
RunWhenAttribute rAttrib = runWhenAttrib as RunWhenAttribute;
if(rAttrib!=null)
{
runWhen = runWhen & rAttrib.RunWhen;
}
}
if (runWhen != 0)
{
Type modelType = objectInstance.GetType();
PropertyInfo modelPropInfo = modelType.GetProperty(prop.Name);
if (!vAttrib.IsValid(modelPropInfo.GetValue(objectInstance, null)))
{
failedProperties[modelPropInfo] = vAttrib.ErrorMessage;
return false;
}
else
{
failedProperties[modelPropInfo] = string.Empty;
}
if (prop.GetType() == typeof(EntityObject))
{
IValidationProvider ivp = Activator.CreateInstance(prop.GetType()) as IValidationProvider;
ivp.IsValid();
}
}
}
}
}
}
return true;
}
public virtual String[] ValidationErrorMessages
{
get
{
return failedProperties.Values.ToArray();
}
}
public virtual IDictionary PropertiesValidationErrorMessages
{
get { return failedProperties; }
}
#endregion
private PropertyInfo[] GetProperties(Type type)
{
if (properties == null || properties.Length == 0)
properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
return properties;
}
}
}
最后T4产生的实体类效果的部分代码:
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmEntityTypeAttribute(NamespaceName="ChildrenModel", Name="Customer")]
[Serializable()]
[DataContractAttribute(IsReference=true)]
public partial class Customer : EntityObject ,IValidationProvider, IDataErrorInfo
{
#region IDataErrorInfo Members
string IDataErrorInfo.Error
{
get
{
StringBuilder errors=new System.Text.StringBuilder();
foreach (string str in ValidationProvider.ValidationErrorMessages)
{
errors.Append(str);
}
return errors.ToString();
}
}
string IDataErrorInfo.this[string column]
{
get
{
Type t = this.GetType();
PropertyInfo info = t.GetProperty(column);
string errorMessage = string.Empty;
if (info != null)
errorMessage = ValidationProvider.PropertiesValidationErrorMessages[t.GetProperty(column)] as string;
if (errorMessage == null)
errorMessage = string.Empty;
return errorMessage;
}
}
#endregion
private IValidationProvider validationProvider;
IValidationProvider ValidationProvider
{
get
{
if (validationProvider == null)
validationProvider = new EntityObjectValidationProvider(this);
return validationProvider;
}
}
#region IValidationProvider Members
/// <summary>
/// Performs the fields validation. Returns true if no
/// validation error was found.
/// </summary>
/// <returns></returns>
/// <remarks>Forwards the call to <see cref="ActualValidator"/>.</remarks>
public virtual bool IsValid()
{
return ValidationProvider.IsValid();
}
public virtual String[] ValidationErrorMessages
{
get { return ValidationProvider.ValidationErrorMessages; }
}
public virtual IDictionary PropertiesValidationErrorMessages
{
get { return ValidationProvider.PropertiesValidationErrorMessages; }
}
#endregion