这块完全是扒了@何镇汐大神博客里的教程实现的,在这之前完全没想到数据验证居然可以这样做!!在此表示严重感谢!!!
点击这里可以去了解这个方法的原理,老胡估计自己是完全说不清楚的了。 http://www.cnblogs.com/xiadao521/p/4111815.html
还是来图上看
Validation部分,这里是从@何镇汐教程中拔过来的代码,
老胡只是在_BaseEntityValidation类里面进行了简单的集成进来。
1 namespace CAMCOCO.Model.Core.Entity 2 { 3 using System.Collections.Generic; 4 using Validation; 5 6 public partial class _BaseEntityValidation 7 { 8 private readonly List<IValidationRule> _validationRules; 9 private ValidationHandler _validationHandler; 10 11 protected _BaseEntityValidation() 12 { 13 _validationRules = new List<IValidationRule>(); 14 _validationHandler = new ValidationHandler(); 15 } 16 17 public override void Dispose() 18 { 19 base.Dispose(); 20 _validationRules.Clear(); 21 } 22 23 /// <summary> 24 /// 为实体对象添加一条验证规则 25 /// </summary> 26 /// <param name="rule">验证规则</param> 27 public void addValidationRule(IValidationRule rule) 28 { 29 if (rule != null) 30 { 31 _validationRules.Add(rule); 32 } 33 } 34 35 /// <summary> 36 /// 对实体对象进行合法性验证,如果验证失败,将通过throw Exception进行抛出 37 /// </summary> 38 public void validate() 39 { 40 IValidationResultCollection results = getValidationResult(); 41 _validationHandler.handle(results); 42 } 43 44 private IValidationResultCollection getValidationResult() 45 { 46 IValidationResultCollection result = ValidationFactory.createValidationor().validate(this); 47 foreach (var rule in _validationRules) 48 result.addResult(rule.validate()); 49 return result; 50 } 51 52 53 54 } 55 }
有了这个神器,在业务逻辑层里实现数据验证简直就是一种享受。
下面是在业务层调用的时候的代码样子:
1 public void addPopedomGroup(PopedomGroup obj) 2 { 3 try 4 { 5 IRepository<PopedomGroup> res = createRepository<PopedomGroup>(); 6 7 PopedomGroup dbObj = PopedomGroupFactory.createPopedomGroup(); 8 dbObj.cloneFromWithProperties(obj, "Name", "IsHidden"); 9 dbObj.Order.Index = createNewOrderIndex<PopedomGroup>(); 10 11 dbObj.addValidationRule(new PopedomGroupCannotExistsSameNameRule(res, dbObj)); 12 dbObj.validate(); 13 res.add(dbObj); 14 commit(); 15 } 16 catch (Exception ex) 17 { 18 throw ex; 19 } 20 }
dbObj.addValidationRule(new PopedomGroupCannotExistsSameNameRule(res, dbObj));
这句代码可以很方便地在本次逻辑操作中加入任何的验证条件,而验证规则的编写也很简单, 同时可以实现任意组合 。
例如:
1 namespace CAMCOCO.Business.Authentication.Rule 2 { 3 using System.ComponentModel.DataAnnotations; 4 using CAMCOCO.Business.Core.Rule; 5 using CAMCOCO.Model.Core.Validation; 6 using CAMCOCO.Data; 7 using CAMCOCO.Model.Authentication.Entity; 8 9 public class PopedomGroupCannotExistsSameNameRule : BaseRule<PopedomGroup> 10 { 11 public PopedomGroupCannotExistsSameNameRule(IRepository<PopedomGroup> res, PopedomGroup checkObj) 12 : base(res, checkObj) 13 { 14 15 } 16 17 public override ValidationResult validate() 18 { 19 ValidationResult result = ValidationResult.Success; 20 if (_res.exists(m => m.Id != _checkObj.Id && m.System.DeleteFlag == false && m.Name == _checkObj.Name)) 21 { 22 result = createValidationResult("PopedomGroup", "权限组名称不能重复"); 23 } 24 return result; 25 } 26 } 27 }
OK,到此为止,老胡的实体模型基类基本就搭建完毕了,在老胡的架构里,所有的实体类都必须从三大基类(BaseEntityNormal, BaseEntityOrder, BaseEntityTree)派生而来,具备如下一些特性:
其实这个问题展开来还有一系列的考虑,在之前的项目经验中,我采用过两种形式的ID,一种是数据库自增标识,一种是Guid。两种方式分别都有自己的优点,自增标识属于数据库自主管理,我们写代码的时候不同进行维护,同时所有ID号都是连续的,优点是方便记忆,能够快速定位数据,够直观。同时缺点也是明显的,由于自增特性,我们没法手工任意修改,当需要做数据迁移或者在系统之间导入导出数据时,这个东西很麻烦,你得先建立一个临时表用于记录新老ID对应记录等等,同时因为其是连续的数字,如果在安全验证上出现漏洞,很容易就被用户调取到不属于自身范围的数据。而GUID正好解决以上两个问题,同时GUID带来的问题就是无法记忆无法推算,在开发及测试程序时无法很好地预判结果和肉眼查找数据。
在老胡做这个架构的时候,两种方案都尝试了,最终为了保留EF中的某些重要特性,比如GUID模式通过EF无法自动生成符合老胡要求的主键,我希望数据的保存依托ID作为主键同时是一个聚集索引,但GUID明显不适合做聚集索引。手工制表的时候老胡一般都是吧GUID作为主键,然后去掉聚集索引,将聚集索引建立在数据创建时间字段上。
7、实体模型可以被业务层及以上的任意层使用,但以为除了业务层意外均不掌握修改实体的方法,所以实体数据的安全性得到了保障,要修改实体内容,只能通过业务层;
8、通过EntityBuilder建造者来初始化实体基类信息,派生类中不用关心其基类部分的属性该如何赋值;
1、凡是有查询需求的实体,都因为为其构造Filter,而这些Filter都必须派生自BaseFilter;
2、BaseFilter中已经将实体基类中的标准属性进行了定义,派生类中只需要针对派生实体的特定属性进行特定扩展即可;
3、Filter本身不应该有任何操作功能,只是一堆属性定义(和贫血实体一样);
4、Filter的目的是取代查询函数里的一大堆参数而存在的
1 //普通查询接口 2 IQueryable<Entity> findEntityList(long id, string searchName, int maxThanAge, ...); 3 4 //采用Filter模式 5 class EntityFilter{ 6 public int Id{get;set;} 7 public string searchName{get;set;} 8 public int maxThanAge{get;set;} 9 //... 10 } 11 12 IQueryable<Entity> findEntityList(EntityFilter filter);