紧接着上面的内容,我们继续看下动态模型页面交互实现方式,内容如下:

1,如何实现动态表单

2,如何接收表单数据并绑定到动态模型上

一、如何实现动态表单

由于模型信息都是后台自定义配置的,并不是固定不变的结构,所以没有办法直接在页面上写出对应的表单数据,而需要通过解析模型的结构,动态的生成对应的表单。在说具体实现方法前,我们先来看下我们想要达到的效果。

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

FormGenerator.Generate包含两个参数,一个动态模型对象,一个需要呈现的属性列表,方法返回最终生成的form表单html,然后通过Html.Raw呈现到页面上。

下面介绍一下实现过程,首先定义一个IDynamicFormGenerator接口,代码如下:

   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?我们再来看下前面定义的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等
}
}

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

  

  到此表单就可以呈现到界面上了。

二、如何接收表单数据并绑定到动态模型上

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

  

所有代码还是需要大家自己完善补充,如果有不足之处,欢迎大家能够批评指正。

  

EFcore与动态模型(三)的更多相关文章

  1. EFcore与动态模型

    在开发商城系统的时候,大家会遇到这样的需求,商城系统里支持多种商品类型,比如衣服,手机,首饰等,每一种产品类型都有自己独有的参数信息,比如衣服有颜色,首饰有材质等,大家可以上淘宝看一下就明白了.现在的 ...

  2. EFcore与动态模型(二)

    上篇文章中介绍了如何使用ef进行动态类型的管理,比如我们定义了ShopDbContext并且注册了动态模型信息,下面的代码实现了动态信息的增加: Type modelType = IRuntimeMo ...

  3. EntityFramework Core如何映射动态模型?

    前言 本文我们来探讨下映射动态模型的几种方式,相信一部分童鞋项目有这样的需求,比如每天/每小时等生成一张表,此种动态模型映射非常常见,经我摸索,这里给出每一步详细思路,希望能帮助到没有任何头绪的童鞋, ...

  4. OSGI(面向Java的动态模型系统)

    基本简介编辑 OSGI服务平台提供在多种网络设备上无需重启的动态改变构造的功能.为了最小化耦合度和促使这些耦合度可管理,OSGi技术提供一种面向服务的架构,它能使这些组件动态地发现对方.OSGi联 O ...

  5. 菜鸟学SSH(十八)——Hibernate动态模型+JRebel实现动态创建表

    项目用的是SSH基础框架,当中有一些信息非常相似,但又不尽同样.假设每个建一个实体的话,那样实体会太多.假设分组抽象,然后继承,又不是特别有规律.鉴于这样的情况.就打算让用户自己配置要加入的字段,然后 ...

  6. UML动态模型图简单介绍

    UML动态模型图描述了系统动态行为的各个方面,包括用例图.序列图.协作图.活动图和状态图.下面就每种图做一个简单介绍: 用例图 用例图描述系统外部的执行者与系统提供的用例之间的某种联系.所谓用例是指对 ...

  7. [Unity3D][Vuforia][IOS]vuforia在unity3d中添加自己的动态模型,识别自己的图片,添加GUI,播放视频

    使用环境 unity3D 5 pro vuforia 4 ios 8.1(6.1) xcode 6.1(6.2) 1.新建unity3d工程,添加vuforia 4.0的工程包 Hierarchy中 ...

  8. [Beego模型] 三、高级查询

    [Beego模型] 一.ORM 使用方法 [Beego模型] 二.CRUD 操作 [Beego模型] 三.高级查询 [Beego模型] 四.使用SQL语句进行查询 [Beego模型] 五.构造查询 [ ...

  9. OSGI 面向Java的动态模型系统

    OSGI (面向Java的动态模型系统) OSGi(Open Service Gateway Initiative)技术是Java动态化模块化系统的一系列规范.OSGi一方面指维护OSGi规范的OSG ...

随机推荐

  1. 3. 托管对象模型的迁移(Core Data 应用程序实践指南)

    本章介绍如何添加模型版本及模型映射,演示几种迁移技术,供在升级模型时使用. 3.1. 修改托管对象模型 3.2. 添加模型版本 3.3. 轻量级迁移方式 3.4. 默认的迁移方式 3.5. 通过迁移管 ...

  2. MySQL 安装 5.0

    MySQL免安装版配置 1.下载 MySQL 免安装版 2.将 MySQL 解压到待安装目录,使用%MYSQL_HOME%表示 3.打开文件my-huge.ini另存为my.ini,在my.ini文件 ...

  3. andorid 开放工具集合

    1.开放工具集合 http://www.androiddevtools.cn/

  4. jQuery插件开发详解

    我们该如何扩展jQuery呢?主要可以通过下面2个来扩展:$.extend 和 $.fn $.extend如果把jQuery当成一个类,$.extend相当于为该类添加了静态方法extend. < ...

  5. apache 做负载

    首先说明一下,我感觉这种办法不太好,不能叫负载吧.不知道跳转到的服务器把数据返回给用户,还通不通过Apache的服务器,还有就是不能断点下载了 方法 1.打开httpd.conf  把如下模块前面的# ...

  6. --@angularJS--一个最简单的指令demo

    <!DOCTYPE HTML><html ng-app="app"><head>    <title>custom-directiv ...

  7. systemd的命令systemctl set-property testSpeed CPUQuota=10%

    总结 systemd 的资源限制一般要写到unit文件中,但是,现在测试发现会有 被值被覆盖的现象:经过排查发现是,没有 使用systemd的接口,凡是使用echo "" > ...

  8. oracle11g手工建库

    1.设置环境变量 [oracle@HE3~]$ vi .bash_profile exportPATH exportEDITOR=vi exportORACLE_SID=orcl exportORAC ...

  9. Raphael初始化,path,circle,rect,ellipse,image

    path jsp: <%@ page language="java" contentType="text/html; charset=UTF-8" pag ...

  10. vue初探

    vue初探 很多同学一定都听过MVVM.组件.数据绑定之类的专业术语,而vue框架正是这样的一种框架.vue的作用是:通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件. 第一部分:vue介 ...