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

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. pageX,clientX,offsetX,layerX的那些事

    在各个浏览器的JS中,有很多个让你十分囧的属性,由于各大厂商对标准的解释和执行不一样,导致十分混乱,也让我们这些前端攻城狮十分无语和纠结>_< John Resig大神说过,动态元素有3个 ...

  2. Android应用性能优化方案

    1.避免创建不必要的对象 2.如果方法用不到成员变量,可以把方法声明为静态(static),这样性能会提高百分之十五到百分之二十 3.避免使用get/set存取字段,可以把字段声明为public直接访 ...

  3. 2.10. 代码片段:demo方法(Core Data 应用程序实践指南)

    该代码段我觉得没有太多东西 - (void)applicationDidBecomeActive:(UIApplication *)application { [self cdh]; [self de ...

  4. CSS设置图片居中的方法

    如果是应用了表格,那么设置单元格为align="center"就可以使其中的一切内容居中.如果没有应用表格要想设置图片居中就有点困难了.困难来自不按"常规出牌" ...

  5. Android3.0 以前的Fragment支持

    Fragment非常实用,Android也为3.0以前的平台增加了Fragment支持,只是该Fragment不是继承android.app.Fragment,而是继承android.support. ...

  6. JSP 禁用脚本设置

    JSP 禁用脚本设置: web.xml: <?xml version="1.0" encoding="UTF-8"?> <web-app xm ...

  7. DataTables学习:从最基本的入门静态页面,使用ajax调用Json本地数据源实现前端开发深入学习,根据后台数据接口替换掉本地的json本地数据,以及报错的处理地方,8个例子(显示行附加信息,回调使用api,动态显示和隐藏列...),详细教程

    一.DataTables  个人觉得学习一门新的插件或者技术时候,官方文档是最根本的,入门最快的地方,但是有时候看完官方文档,一步步的动手写例子,总会出现各种莫名其妙的错误,需要我们很好的进行研究出错 ...

  8. GDB中的backtrace命令

    backtrace命令,可以用于回溯函数调用栈. 例如:当出现段错误的时候,执行backtrace,可以看到是哪里的调用,产生的这个段错误.

  9. linux上静态库链接的有关问题

    求大神,linux下静态库链接的问题有两个文件和一个库,a.c, b.c,libh.a,其中b.c里面会有调用libh.a的函数func1,现在将a.c, b.c,libh.a编译链接生成可执行文件, ...

  10. 《JAVASCRIPT高级程序设计》节点层次和DOM操作技术

    DOM可以将任何HTML和XML文档描绘成一个由多层次节点构成的结构.节点分为几种不同的类型,每种类型分别表示文档中不同的信息,每种类型都继承与Node接口,因此都共同享有一些属性和方法,同时,也拥有 ...