昨天咱們一直在作準備工做,最終表單數據須要從數據庫裏提取,並保存到數據庫,今天接着介紹如何作提取、保存和驗證。數據庫
4、提取並顯示信息app
在EditForm咱們定義一個InfoId屬性,用於接收在列表頁面打開編輯窗體時傳遞主鍵,而後編輯窗體經過主鍵查詢實體,最終填充到映射好的控件上。ide
/// <summary> /// 獲取或設置信息ID,根據此ID查詢實體並填充在窗體上。 /// </summary> public string InfoId { get; set; }
在窗體的Load事件中,判斷InfoId是否爲空,若是不空則查詢出實體對象,將數據填充到各控件。ui
private void EditForm_Load(object sender, EventArgs e) { if (!DesignMode) { LoadInfo(); } } /// <summary> /// 讀取實體信息,顯示在窗體上。 /// </summary> protected virtual void LoadInfo() { if (EntityType == null || EntityPropertyExtend == null) { Helper.ShowError("沒有綁定 EntityType 或 EntityPropertyExtend。"); return; } if (!string.IsNullOrEmpty(InfoId)) { using (var persister = new EntityPersister(EntityType)) { var entity = persister.First(InfoId) as IEntity; if (entity == null) { return; } FillEntityValues(entity); } } } /// <summary> /// 將實體的屬性值填充到窗體上。 /// </summary> /// <param name="entity"></param> protected virtual void FillEntityValues(IEntity entity) { foreach (var kvp in EntityPropertyExtend.GetProperties()) { var value = entity.GetValue(kvp.Value); if (value == null || value.IsEmpty) { continue; } var converter = ControlEntityMapHelper.GetMapper(kvp.Key.GetType()); if (converter != null) { converter.SetValue(kvp.Key, value.GetStorageValue()); } } }
5、數據驗證並保存spa
Fireasy.Data.Entity基於System.ComponentModel.DataAnnotations實現了內部的驗證機制。在持久化對象Create和Update以前,會調用ValidationUnity對實體對象進行驗證。3d
在窗體上,咱們仍是使用了ErrorProvider組件來顯示驗證提示信息。code
private void btnSave_Click(object sender, EventArgs e) { SaveData(); } /// <summary> /// 保存表單數據到數據庫。 /// </summary> /// <param name="createNew">保存後是否新建信息。</param> /// <returns></returns> protected virtual IEntity SaveData(bool createNew = false) { if (EntityType == null || EntityPropertyExtend == null) { Helper.ShowError("沒有綁定 EntityType 或 EntityPropertyExtend。"); return null; } //清理驗證錯誤的提示 errorProvider1.Clear(); try { using (var persister = new EntityPersister(EntityType)) { var entity = (string.IsNullOrEmpty(InfoId) ? persister.NewEntity() : persister.First(InfoId)) as IEntity; if (entity == null) { return null; } ReadEntityValues(entity); var infoId = string.Empty; if (entity.EntityState == EntityState.Attached) { infoId = SetPrimaryProperty(entity); } persister.Save(entity); if (entity.EntityState == EntityState.Attached) { InfoId = infoId; } Helper.ShowInformation("數據保存成功。"); return entity; } } catch (EntityInvalidateException exp) { ShowPropertyInvalidateMessages(exp); } catch (Exception exp) { var log = LoggerFactory.CreateLogger(); if (log != null) { log.Error("[" + EntityType + "]保存數據失敗", exp); } Helper.ShowError("數據保存失敗。", exp); } return null; }
ReadEntityValues方法用於從窗體控件中讀取數據,而後寫入到實體對象中。orm
/// <summary> /// 讀取窗口上的控件值,寫給實體屬性。 /// </summary> /// <param name="entity"></param> protected virtual void ReadEntityValues(IEntity entity) { foreach (var kvp in EntityPropertyExtend.GetProperties()) { var converter = ControlEntityMapHelper.GetMapper(kvp.Key.GetType()); if (converter != null) { var value = converter.GetValue(kvp.Key); var property = PropertyUnity.GetProperty(EntityType, kvp.Value); entity.SetValue(kvp.Value, PropertyValue.New(value, property.Type)); } } }
PropertyValue是Fireasy.Data.Entity中的類,能夠參考Fireasy.Data.Entity組件。
SetPrimaryProperty用於手動設置主鍵的值。對象
/// <summary> /// 設置主鍵的值,並返回主鍵屬性。 /// </summary> /// <param name="entity"></param> /// <returns></returns> private string SetPrimaryProperty(IEntity entity) { var keyValue = Guid.NewGuid().ToString("N"); var accessor = entity as IEntityPropertyAccessor; var pk = PropertyUnity.GetPrimaryProperties(EntityType).FirstOrDefault(); accessor.SetValue(pk, keyValue); return keyValue; }
若是實體驗證失敗,會拋出一個EntityInvalidateException類型的異常信息,該對象包括驗證失敗的各個屬性及對應的錯誤信息,以及在實體類型上定義的全局驗證特性,即不是單一的屬性值驗證,而是業務邏輯驗證。blog
/// <summary> /// 顯示驗證失敗的信息。 /// </summary> /// <param name="exp"></param> private void ShowPropertyInvalidateMessages(EntityInvalidateException exp) { var sb = new StringBuilder(); foreach (var property in exp.PropertyErrors) { //查找有沒有驗證失敗屬性相關聯的控件 var map = EntityPropertyExtend.GetProperties().Where(s => s.Value == property.Key.Name).FirstOrDefault(); if (map.Key == null) { sb.AppendLine(string.Join("\n", property.Value.ToArray())); continue; } //在控件上顯示驗證失敗的信息 errorProvider1.SetError(map.Key, string.Join("\n", property.Value.ToArray())); } if (sb.Length > 0) { Helper.ShowError("填寫的數據不完整,還包括如下這些信息:\n" + sb.ToString()); } }
6、運行實例
運行程序,查看前面咱們定義的ProductEdit窗體。
咱們從列表中雙擊一條數據進行編輯,Book的相關數據自動填充到了控件中。
咱們把個別的文本清空,或是輸入較長的字符串,這時將保存失敗,並在窗體上顯示紅色的圖標。
7、驗證類的定義
最後,將Book的驗證類貼上來,以便更直觀。
//若是要啓用實體驗證,請使用如下特性,並在 BookMetadata 中定義驗證特性。 [MetadataType(typeof(BookMetadata))] public partial class Book { } public class BookMetadata { /// <summary> /// 屬性 Id 的驗證特性。 /// </summary> [Required] [StringLength(32)] public object Id { get; set; } /// <summary> /// 屬性 ISBN 的驗證特性。 /// </summary> [StringLength(10)] public object ISBN { get; set; } /// <summary> /// 屬性 BarCode 的驗證特性。 /// </summary> [Required] [StringLength(13)] public object BarCode { get; set; } /// <summary> /// 屬性 PyCode 的驗證特性。 /// </summary> [StringLength(20)] public object PyCode { get; set; } /// <summary> /// 屬性 Name 的驗證特性。 /// </summary> [Required] [StringLength(20)] public object Name { get; set; } /// <summary> /// 屬性 Price 的驗證特性。 /// </summary> [Required] public object Price { get; set; } /// <summary> /// 屬性 Agio 的驗證特性。 /// </summary> [Required] public object Agio { get; set; } /// <summary> /// 屬性 Unit 的驗證特性。 /// </summary> [Required] [StringLength(4)] public object Unit { get; set; } /// <summary> /// 屬性 SizeNo 的驗證特性。 /// </summary> [StringLength(10)] public object SizeNo { get; set; } /// <summary> /// 屬性 MediaNo 的驗證特性。 /// </summary> [StringLength(10)] public object MediaNo { get; set; } /// <summary> /// 屬性 VolumesOfBar 的驗證特性。 /// </summary> public object VolumesOfBar { get; set; } /// <summary> /// 屬性 BarsOfBag 的驗證特性。 /// </summary> public object BarsOfBag { get; set; } /// <summary> /// 屬性 Emphasis 的驗證特性。 /// </summary> public object Emphasis { get; set; } /// <summary> /// 屬性 TypeCode 的驗證特性。 /// </summary> [StringLength(10)] public object TypeCode { get; set; } /// <summary> /// 屬性 PublisherId 的驗證特性。 /// </summary> [StringLength(32)] public object PublisherId { get; set; } /// <summary> /// 屬性 PublishDate 的驗證特性。 /// </summary> public object PublishDate { get; set; } /// <summary> /// 屬性 UpperLimit 的驗證特性。 /// </summary> [Required] public object UpperLimit { get; set; } /// <summary> /// 屬性 LowerLimit 的驗證特性。 /// </summary> [Required] public object LowerLimit { get; set; } /// <summary> /// 屬性 State 的驗證特性。 /// </summary> public object State { get; set; } /// <summary> /// 屬性 Remark 的驗證特性。 /// </summary> [StringLength(200)] public object Remark { get; set; } /// <summary> /// 屬性 MarkColor 的驗證特性。 /// </summary> [StringLength(6)] public object MarkColor { get; set; } /// <summary> /// 屬性 DelFlag 的驗證特性。 /// </summary> public object DelFlag { get; set; } }