Winform快速開發組件的實現(二)

    昨天咱們一直在作準備工做,最終表單數據須要從數據庫裏提取,並保存到數據庫,今天接着介紹如何作提取、保存和驗證。數據庫

 

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

    }
相關文章
相關標籤/搜索