不使用反射,“一行代码”实现Web、WinForm窗体表单数据的填充、收集、清除,和到数据库的CRUD

简介:

问题篇:

    昨天在CSDN看到这样一个帖子:“苦逼的三层代码”:

复制代码
采用传统的三层架构写代码,每个数据表都要定义一个实体对象,编写后台的时候,
Web层需要针对页面的用户输入逐个手动编写赋值到实体对象的各个属性,然后DAL层还要用SqlHelper 进行各个存储过程对应参数的实体赋值,
我的天呀,写几个表还好,多个表呢,
写的后台都没力气,
典型的苦逼代码工没营养,各位有啥好的处理方法或开发方式。。
复制代码

 

    看到跟帖,大部分都说使用ORM解决这个问题,但我觉得ORM还是没有解决贴主的几个问题:

  1. 每个数据表都要定义一个实体对象
  2. 页面的用户输入逐个手动编写赋值到实体对象的各个属性
  3. 表很多,代码重复量大,典型的苦逼代码工

    另外跟帖中也有不少上用动软的三层代码生成器,这个方法看似能够解决一部分问题,但必须使用代码生成器规定的那种三层结构,不利于灵活扩展,而且遇到业务稍复杂的情况,也不是代码生成器能够解决的问题。

    实际上,对于问题1,问题2,我们按照一定规则,使用反射是可以解决对象属性手工逐个赋值、取值的过程的,需要我们自己好好制定这个规则。这里我采用另外一种方案,不使用反射,“一行代码”实现Web、WinForm窗体表单数据的填充、收集、清除,和到数据库的CRUD,而秘诀就是对表单控件进行扩展。

原理篇:


    我们常用的表单控件主要有以下几个:

  • CheckBox、
  • DropDownList、
  • Label、
  • ListBox、
  • RadioButton、
  • TextBox

    我们对这些控件进行扩展,让它统一继承一个数据接口 IDataControl:

IDataControl接口

    稍后我们来讲这个接口的具体应用,下面,我们定义几个新的数据控件,来继承这个接口:
    注:下面以WinForm控件为例子,WebForm与之类似。

复制代码
public partial class DataCalendar : DateTimePicker, IDataControl
{
//数据日历控件
}

public partial class DataCheckBox : CheckBox, IDataControl
{
//数据复选框控件
}

public partial class DataDropDownList : ComboBox, IDataControl
{
//数据下拉选择框控件
}

public class DataLabel : Label, IDataControl
{
//数据标签控件
}

public partial class DataListBox : ListBox, IDataControl
{
//数据列表框控件
}

public partial class DataRadioButton : RadioButton, IDataControl
{
//数据选项按钮控件
}

public class DataTextBox : TextBox, IDataTextBox
{
//数据文本框控件
}
复制代码

    有了这些扩展的表单控件,我们只需要调用它的接口方法,进行赋值和取值:

DataTextBox dtb=new DataTextBox();
dtb.SetValue("text1");
string value=dtb.GetValue().ToString();//text1

    而在DataTextBox的这两个接口方法实现中,是不需要使用反射的:

复制代码
       public void SetValue(object obj)
        {
            if (obj == null || obj.ToString() == "")
            {
                this.Text = "";
                return;
            }
            //其它检测和格式控制代码略
            this.Text = obj.ToString().Trim();
        }

        public object GetValue()
        {
           //其它检测和格式控制代码略
            return this.Text.Trim();
        }
复制代码

    有了数据控件的这2个接口方法,我们对各种数据控件进行统一的数据收集、填充就很容易了,无非就是遍历一下窗体上面的数据控件,找到它们然后一个个处理即可,具体代码后面的实例会说到。


    既然说到表单数据的填充,将查询出来的数据集中哪个表的某个字段和哪个控件对应呢?
    这就用到了IDataControl接口的下面2个属性了:

string LinkProperty{get;set;}//对应字段名或者实体类的属性名
string LinkObject{get;set;}//对应表名或者实体类的类名称

    OK,有了IDataControl接口的这几个接口方法和属性,不使用反射,封装一下,“一行代码”实现Web、WinForm窗体表单数据的填充、收集、清除,和到数据库的CRUD,也就不是难事了。

实战篇:


    按照这个方法,我在PDF.NET开发框架中实现了本文标题说的功能,最近还做了一个简单的例子,大家可以去开源项目网站下载:
    项目网址: http://pwmis.codeplex.com 到下载页,选择“ PDF.Net_V4.6 WinForm 数据表单实例 ”这个下载链接即可。

    下面说说这个小程序的搭建过程,

1,新建项目

    首先创建一个WinForm程序项目,引入下面几个DLL类库:

 

2,添加数据控件到工具箱

    因为是WinForm项目,所以我们引用了PWMIS.Windows.dll, 它包含了我们需要的数据控件。
    找到该文件,将它拖入我们的工具箱:

    添加前,在工具箱中增加一个项:PDF.NET DataForm,然后在资源管理器中选择Windows数据控件组件的文件,将它“拖放”到刚才建立的 PDF.NET DataForm下面

 

    这是拖放后,添加PDF.NET Windows 数据控件成功后的工具箱样子。

 

3,添加数据窗体

    我们在主窗体上放置几个按钮和一个网格控件,以便增、删、改、查询数据:

    然后我们再新建立一个窗体 Form2 ,在上面放置几个我们需要的表单控件并设置好我们需要保存的表名称和对应的字段名称:

 

4,编写代码

    4.1,基础CRUD代码

    窗体建立好了,现在开始写代码,刚开始还没有数据库呢,这里我们是有Access数据库文件,方便我们测试,在“创建数据库”按钮事件里面写如下代码:

复制代码
private void btnCreateDB_Click(object sender, EventArgs e)
        {
            string dbpath = Application.StartupPath + "\\TEST.mdb";
            if (!File.Exists(dbpath))
            {
                //创建数据库文件
                PWMIS.AccessExtensions.AccessUility.CreateDataBase(dbpath);
                //创建表
                Access access = new Access();
              access.ConnectionString = "Provider=Microsoft.Jet.Oledb.4.0;Data Source=" + dbpath;

              PWMIS.AccessExtensions.AccessUility.CreateTable(access, new User());
                //配置连接
                PWMIS.AccessExtensions.AccessUility.ConfigConnectionSettings("AccessConn", dbpath);

                MessageBox.Show("创建数据成功!");
                this.btnInsert.Enabled = true;
                this.btnUpdate.Enabled = true;
                this.btnDelete.Enabled = true;
            }
            else
            {
                MessageBox.Show("数据库已经创建过了,如需重新创建,请先删除数据库文件。");
            }
           
        }
复制代码

    注意,我们并没有手工去创建数据表,而是利用事先定义好的PDF.NET实体类 User,在Access数据库中自动创建了一个数据表的:

 PWMIS.AccessExtensions.AccessUility.CreateTable(access, new User());

    User实体类的定义很简单,它内部指明了实体类将要映射到的表名和实体类属性映射的字段名:

User实体类定义

   实体类是事先手写好的,表结构是后来程序运行时创建的,这也算是PDF.NET的CodeFirst 功能吧!

    下面,写主窗体的数据加载代码:

 List<User> list = OQL.From<User>().Select().END.ToList<User>();
this.dataGridView1.DataSource =list;

    这里用上了PDF.NET框架的OQL扩展,一行代码查询数据,需要项目引用PWMIS.Core.Extensions.dll 以及
    using PWMIS.Core.Extensions;

 

    修改数据也是一行代码:

 User user = this.dataGridView1.CurrentRow.DataBoundItem as User;
 EntityQuery<User>.Instance.Update(user);

 

    重头戏在我们的Form2.cs 中,我们看看提交按钮里面,是怎么收集、更新表单数据的:

复制代码
 private void btnSubmit_Click(object sender, EventArgs e)
{
  //前面检查数据的代码略
   var ibCommandList = MyWinForm.Instance.AutoUpdateIBFormData(this.Controls);
}
复制代码

    就这一行代码就足够了,不需要使用任何实体类之类的,直接保存(Insert、Update)数据到数据库,框架会自动判断当前是新增还是修改,而根据就是看“主键数据控件”是否有值。


    如果要清除表单数据,重新录入数据也很简单:

  private void btnClear_Click(object sender, EventArgs e)
        {
            WinFormControlDataMap.ClearData(this.Controls);
        }

 

    4.2,多窗体之间的数据同步   

    在我们这个小例子中,表单窗体(Form2)的数据变化后(新增、修改),可以立即反应到主窗体(Form1)上,而不用主窗体去重新加载数据,这里就必须用到数据绑定集合:

 private BindingList<User> UserBindingList = new BindingList<User>();
//填充集合的代码,就是将数据从数据库查询出来,然后放到该集合中,代码略
this.dataGridView1.DataSource = UserBindingList;

    光有BindingList<T> 集合还不够,它的成员对象还必须实现“属性更改通知”接口INotifyPropertyChanged,而PDF.NET的实体类正好实现了该接口:

public abstract class EntityBase : INotifyPropertyChanged, IEntity, ICloneable
{
//... 略
}

    因此用PDF.NET的实体类来做WinForm、WPF、SL等窗体的数据Model是很合适的,适合在MVVM,MVP模式的项目中使用。

   

    下面,使用框架提供的表单数据收集功能,就很容易的将数据收集到实体类,然后同步更新主窗体的列表数据了,也是一行代码:

 Form1 form1 = this.Owner as Form1;
 User user = form1.GetUserByID(int.Parse(dlbUID.Text));
 //收集数据到实体类中
WinFormControlDataMap.CollectDataToEntityClass(user, this.Controls);

 

5,实例效果

最后,我们来看看这个功能的运行效果图:

增加数据,在新窗体中录入数据

 

单击按钮保存数据,主窗体列表中自动增加一行数据

 

新窗口先不关闭,修改下消费金额,确定,发现主窗口列表的数据被同步修改了。

整个过程没有从数据库去重新刷新数据到主窗口网格控件的,实现了多个窗体之见的数据同步。

 

 

 -----------分界线------------------------

 欢迎加入PDF.NET开发框架 开源技术团队

PDF.NET Ver4.6 开源稳定版发布



    本文转自深蓝医生博客园博客,原文链接:http://www.cnblogs.com/bluedoctor/archive/2013/03/28/2986580.html,如需转载请自行联系原作者



相关文章
【YashanDB知识库】python驱动查询gbk字符集崖山数据库CLOB字段,数据被驱动截断
【YashanDB知识库】python驱动查询gbk字符集崖山数据库CLOB字段,数据被驱动截断
docker快速部署OS web中间件 数据库 编程应用
通过Docker,可以轻松地部署操作系统、Web中间件、数据库和编程应用。本文详细介绍了使用Docker部署这些组件的基本步骤和命令,展示了如何通过Docker Compose编排多容器应用。希望本文能帮助开发者更高效地使用Docker进行应用部署和管理。
62 19
【YashanDB 知识库】用 yasldr 配置 Bulkload 模式作单线程迁移 300G 的业务数据到分布式数据库,迁移任务频繁出错
问题描述 详细版本:YashanDB Server Enterprise Edition Release 23.2.4.100 x86_64 6db1237 影响范围: 离线数据迁移场景,影响业务数据入库。 外场将部分 NewCIS 的报表业务放到分布式数据库,验证 SQL 性能水平。 操作系统环境配置: 125G 内存 32C CPU 2T 的 HDD 磁盘 问题出现的步骤/操作: 1、部署崖山分布式数据库 1mm 1cn 3dn 单线启动 yasldr 数据迁移任务,设置 32 线程的 bulk load 模式 2、观察 yasldr.log 是否出现如下错
Hutool创建数据源工厂动态查询不同数据库不同数据表的数据
Hutool创建数据源工厂动态查询不同数据库不同数据表的数据
39 2
基于Flink CDC 开发,支持Web-UI的实时KingBase 连接器,三大模式无缝切换,效率翻倍!
TIS 是一款基于Web-UI的开源大数据集成工具,通过与人大金仓Kingbase的深度整合,提供高效、灵活的实时数据集成方案。它支持增量数据监听和实时写入,兼容MySQL、PostgreSQL和Oracle模式,无需编写复杂脚本,操作简单直观,特别适合非专业开发人员使用。TIS率先实现了Kingbase CDC连接器的整合,成为业界首个开箱即用的Kingbase CDC数据同步解决方案,助力企业数字化转型。
96 5
基于Flink CDC 开发,支持Web-UI的实时KingBase 连接器,三大模式无缝切换,效率翻倍!
Python 高级编程与实战:深入理解 Web 开发与 API 设计
在前几篇文章中,我们探讨了 Python 的基础语法、面向对象编程、函数式编程、元编程、性能优化、调试技巧以及数据科学和机器学习。本文将深入探讨 Python 在 Web 开发和 API 设计中的应用,并通过实战项目帮助你掌握这些技术。
|
6月前
|
ServiceStack:不仅仅是一个高性能Web API和微服务框架,更是一站式解决方案——深入解析其多协议支持及简便开发流程,带您体验前所未有的.NET开发效率革命
【10月更文挑战第9天】ServiceStack 是一个高性能的 Web API 和微服务框架,支持 JSON、XML、CSV 等多种数据格式。它简化了 .NET 应用的开发流程,提供了直观的 RESTful 服务构建方式。ServiceStack 支持高并发请求和复杂业务逻辑,安装简单,通过 NuGet 包管理器即可快速集成。示例代码展示了如何创建一个返回当前日期的简单服务,包括定义请求和响应 DTO、实现服务逻辑、配置路由和宿主。ServiceStack 还支持 WebSocket、SignalR 等实时通信协议,具备自动验证、自动过滤器等丰富功能,适合快速搭建高性能、可扩展的服务端应用。
331 3
如何在项目中高效地进行 Web 组件化开发
高效地进行 Web 组件化开发需要从多个方面入手,通过明确目标、合理规划、规范开发、加强测试等一系列措施,实现组件的高效管理和利用,从而提高项目的整体开发效率和质量,为用户提供更好的体验。
134 63