EFcore與動態模型(三)

緊接着上面的內容,咱們繼續看下動態模型頁面交互實現方式,內容以下:html

1,如何實現動態表單數據庫

2,如何接收表單數據並綁定到動態模型上json

1、如何實現動態表單mvc

因爲模型信息都是後臺自定義配置的,並非固定不變的結構,因此沒有辦法直接在頁面上寫出對應的表單數據,而須要經過解析模型的結構,動態的生成對應的表單。在說具體實現方法前,咱們先來看下咱們想要達到的效果。ide

Html.Raw(FormGenerator.Generate(Model,Properties))ui

FormGenerator.Generate包含兩個參數,一個動態模型對象,一個須要呈現的屬性列表,方法返回最終生成的form表單html,而後經過Html.Raw呈現到頁面上。orm

下面介紹一下實現過程,首先定義一個IDynamicFormGenerator接口,代碼以下:htm

   public interface IDynamicFormGenerator
    {
        string Generate(object obj, IEnumerable<RuntimeModelMeta.ModelPropertyMeta> properties);
    }

  接口中只包含一個方法,就是咱們上面實例代碼用到的方法。接口實現邏輯上很簡單,只須要循環每個屬性,根據屬性的特色生成一個表單,並把對象數據綁定到表單上,好比屬性若是是bool類型,咱們能夠生成一個checkbox,而後根據obj對應的屬性值是true仍是false,進而設置checkbox的選中狀態。具體實現代碼:對象

    public class DynamicFormGenerator : IDynamicFormGenerator
    {
        
        public string Generate(object obj, IEnumerable<RuntimeModelMeta.ModelPropertyMeta> properties)
        {
            StringBuilder builder = new StringBuilder();
            //循環屬性集合
            foreach (var item in properties)
            {
                //TODO:根據屬性信息生成表單並綁定數據
         string fieldhtml="";
               //把生成的html加入到stringbulder中
               builder.Append(fieldhtml);

            }
            //返回最終的html結果
            return builder.ToString();
        }
    }

  這個方法裏最主要的部分就是如何根據屬性的類型生成對應的表單,就是如何獲得上面的fieldhtml?咱們再來看下前面定義的RuntimeModelMetablog

public class RuntimeModelMeta
   {
       public int ModelId { get; set; }
       public string ModelName { get; set; }//模型名稱
       public string ClassName { get; set; }//類名稱
       public string Properties{get;set;}//屬性集合json序列化結果
         
       public class ModelPropertyMeta
       {
           public string Name { get; set; }//對應的中文名稱
           public string PropertyName { get; set; } //類屬性名稱
      public int Length { get; set; }//數據長度,主要用於string類型
  
       public bool IsRequired { get; set; }//是否必須輸入,用於數據驗證
       public string ValueType { get; set; }//數據類型,能夠是字符串,日期,bool等
       }
   }

  ModelPropertyMeta裏包含了一個ValueType信息,就是當前屬性的數據類型,那咱們是否能夠根據這個來肯定生成的表單形式?答案是否認的,由於即便是同一種類型也會呈現不一樣的表單,好比都是字符串,可能有的要求呈現下拉框,有的要求呈現複選框,因此只依靠ValueType還不夠,咱們能夠給RuntimeModelMeta增長一個屬性,專門用於設置表單形式的,改造後代碼以下:

public class RuntimeModelMeta
   {
       public int ModelId { get; set; }
       public string ModelName { get; set; }//模型名稱
       public string ClassName { get; set; }//類名稱
       public string Properties{get;set;}//屬性集合json序列化結果
         
       public class ModelPropertyMeta
       {
           public string Name { get; set; }//對應的中文名稱
           public string PropertyName { get; set; } //類屬性名稱
      public int Length { get; set; }//數據長度,主要用於string類型
  
       public bool IsRequired { get; set; }//是否必須輸入,用於數據驗證
       public string ValueType { get; set; }//數據類型,能夠是字符串,日期,bool等
           public string ShowType { get; set; }//表單形式
       }
   }

  

  有了ShowType,咱們就能夠根據設置的類型來生成對應的表單。首先先定義個表單生成器接口,代碼以下:

 public interface IDynamicFormFieldGenerator
    {
        //根據傳遞的屬性及對象,生成表單
        string Generate(object obj, RuntimeModelMeta.ModelPropertyMeta meta,bool onlyform=false);
        //這個表示當前的實現是針對哪種ShowType的
        string ForType { get; }
    }

而後針對每一種ShowType實現一個生成器,好比針對checkbox類型的ShowType,咱們實現一個生成器,代碼以下:

public class CheckboxFieldGenerator : IDynamicFormFieldGenerator
    {
        public string ForType
        {
            get
            {
                return "checkbox";
            }
        }

        public string Generate(object obj, RuntimeModelMeta.ModelPropertyMeta meta,bool onlyform=false)
        {
            //把動態對象轉換成一個DynamicEntity,爲的是後面獲取數據方便,由於DynamicEntity支持經過索引獲取屬性數據
            DynamicEntity entity = obj as DynamicEntity;
            if (obj == null)
            {
                throw new NullReferenceException("DynamicEntity");
            }
            //經過entity[meta.PropertyName]獲取到屬性數據
            return string.Format("<input id='{1}' name='{1}' type='checkbox'  value='{0}'/>",
                 entity[meta.PropertyName]?.ToString(), meta.PropertyName);
            
        }
    }

  

  其餘ShowType類型,能夠根據本身系統的須要,直接實現便可,這裏再也不一一列舉了。

    有了表單構造器,咱們再回頭完善下DynamicFormGenerator,在DynamicFormGenerator中,咱們須要根據屬性的ShowType信息獲取到IDynamicFormFieldGenerator,咱們能夠定義一個DynamicFormFieldGeneratorProvider,方便咱們獲得咱們所須要的IDynamicFormFieldGenerator,具體實現代碼:

    //提供者接口定義
    public interface IDynamicFormFieldGeneratorProvider
    {
        IDynamicFormFieldGenerator Get(string type);
    }
public class DynamicFormFieldGeneratorProvider: IDynamicFormFieldGeneratorProvider
    {
        private readonly IHttpContextAccessor _httpContextAccessor;
        private IEnumerable<IDynamicFormFieldGenerator> _generators;
        public DynamicFormFieldGeneratorProvider(IHttpContextAccessor httpContextAccessor)
        {
            _httpContextAccessor = httpContextAccessor;
        }
        public IDynamicFormFieldGenerator Get(string type)
        {
            //經過依賴注入,獲取到構造器實現集合,因此咱們須要把全部的構造器實現都註冊到ServiceCollection中
            if (_generators==null)
            {
                _generators= _httpContextAccessor.HttpContext.RequestServices.GetServices<IDynamicFormFieldGenerator>(); 
            }
            if (_generators==null)
            {
                throw new NotSupportedException("IDynamicFormFieldGenerator");
            }
            //根據type找到第一個符合條件的構造器,並返回
            IDynamicFormFieldGenerator g = _generators.FirstOrDefault(m => m.ForType == type);
            if (g==null)
            {
                throw new NotSupportedException("not supproted for " + type + "'s form field generator");
            }
            return g;
        }
    }

  

  條件都準備好了,直接完善DynamicFormGenerator,最終代碼以下:

public class DynamicFormGenerator : IDynamicFormGenerator
    {
        private readonly IDynamicFormFieldGeneratorProvider _fieldGeneratorProvider;
        public DynamicFormGenerator(IDynamicFormFieldGeneratorProvider provider)
        {
            _fieldGeneratorProvider = provider;
        }
        public string Generate(object obj, IEnumerable<RuntimeModelMeta.ModelPropertyMeta> properties)
        {
            StringBuilder builder = new StringBuilder();
           
            foreach (var item in properties)
            {
                //根據showtype獲取表單構造器
                IDynamicFormFieldGenerator fieldGenerator = _fieldGeneratorProvider.Get(item.ShowType);
                builder.Append(fieldGenerator.Generate(obj,item));
            }
            return builder.ToString();
        }
    }

  

  到此表單就能夠呈現到界面上了。

2、如何接收表單數據並綁定到動態模型上

在mvc中提供了數據綁定機制,能夠快速的把表單數據綁定到對象上,可是如今咱們的對象是動態的,那又該如何應對?

在表單操做中,當前對應的模型咱們確定知道,因此能夠藉助前面介紹的內容,咱們先獲得一個動態模型對象,具體操做以下:

//根據模型id獲取到type 
Type modelType = _runtimeModelProvider.GetType(modelid);
//實例化
object obj = Activator.CreateInstance(modelType);

  

 咱們如今須要解決的是,如何把動態表單提交的數據綁定到obj的屬性上。方法也很簡單,在mvc中給咱們提供了很好的支持,方法就是TryUpdateModelAsync,藉助這個方法,就能夠很方便的把數據綁定到obj上,具體調用實例

  TryUpdateModelAsync(obj, modelType, "")

  obj就是上面實例化的對象,modelType就是動態模型對應的Type信息,有了數據後,後面就是經過ef完成數據庫同步的事了,好比增長

ShopDbContext.Add(obj);
ShopDbContext.SaveChanges();

  

全部代碼仍是須要你們本身完善補充,若是有不足之處,歡迎你們可以批評指正。

相關文章
相關標籤/搜索