[CAMCOCO][C#]我的系統架構.服務器端.(四)----Model層 實體的自我驗證


這是Model的第二篇,上一篇點這里

 

這塊完全是扒了@何鎮汐大神博客里的教程實現的,在這之前完全沒想到數據驗證居然可以這樣做!!在此表示嚴重感謝!!!

點擊這里可以去了解這個方法的原理,老胡估計自己是完全說不清楚的了。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)派生而來,具備如下一些特性:

1、所有的實體都有唯一的一個ID號。

其實這個問題展開來還有一系列的考慮,在之前的項目經驗中,我采用過兩種形式的ID,一種是數據庫自增標識,一種是Guid。兩種方式分別都有自己的優點,自增標識屬於數據庫自主管理,我們寫代碼的時候不同進行維護,同時所有ID號都是連續的,優點是方便記憶,能夠快速定位數據,夠直觀。同時缺點也是明顯的,由於自增特性,我們沒法手工任意修改,當需要做數據遷移或者在系統之間導入導出數據時,這個東西很麻煩,你得先建立一個臨時表用於記錄新老ID對應記錄等等,同時因為其是連續的數字,如果在安全驗證上出現漏洞,很容易就被用戶調取到不屬於自身范圍的數據。而GUID正好解決以上兩個問題,同時GUID帶來的問題就是無法記憶無法推算,在開發及測試程序時無法很好地預判結果和肉眼查找數據。

在老胡做這個架構的時候,兩種方案都嘗試了,最終為了保留EF中的某些重要特性,比如GUID模式通過EF無法自動生成符合老胡要求的主鍵,我希望數據的保存依托ID作為主鍵同時是一個聚集索引,但GUID明顯不適合做聚集索引。手工制表的時候老胡一般都是吧GUID作為主鍵,然后去掉聚集索引,將聚集索引建立在數據創建時間字段上。

2、所有實體都會記錄下創建時間;

3、所有實體都是邏輯刪除;

4、Order類實體可以通過框架標准接口進行排序;

5、Tree類實體可以通過框架標准接口進行排序操作和節點操作;

6、所有實體都具備完整的自我合法性驗證功能;

7、實體模型可以被業務層及以上的任意層使用,但以為除了業務層意外均不掌握修改實體的方法,所以實體數據的安全性得到了保障,要修改實體內容,只能通過業務層;

8、通過EntityBuilder建造者來初始化實體基類信息,派生類中不用關心其基類部分的屬性該如何賦值;

 

BaseFilter的特性:

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);

 

 

這是Model的第二篇,上一篇點這里

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM