接触LLBL Gen Pro 对象关系映射框架后 前途变的一片光明
时间回到2010年,那时候还是熟悉代码生成+基础框架这种模式,基本的开发思路是通过代码生成器生成实体,再生成接口与实现类,最后拖拉控件,写界面数据绑定代码。基本上就是动软代码生成器给出的模式,或是微软的Repository Factory模式的实践,迷恋于微软的Enterprise Libray,这个框架是从Application Block演化而来。我也是算是.NET技术推广以来,第一批学习.NET技术的开发人员。
一直在寻找一种界面与逻辑分离的技术,也没有思路,上面代码生成造成的结果是逻辑代码分布在系统的各个地方,改一个字段或是增加字段都需要重新生成一次,给系统的稳定性带来困扰。用《企业应用架构模式》中的一种模式总结,就是事务脚本(Transaction Script),不过这种模式好理解,也没有复杂的技术堆栈,通过对这种模式的掌握,由.NET学习者变成熟练的.NET代码工人。
第一次看到LLBL Gen Pro,它长成这个样子:
LLBL Gen Pro 2.5/2.6是它发展历史上很经典的一个版本,查询接口稳定成熟,遇到问题了去tinyform上发个帖子,过一会就有专业的人员响应回复。经过大半年的学习,熟悉了这个ORM框架的用法,开始高级一点的定制开发,它的模板编辑器如下面的图所示:
LLBL Gen Pro从3.x开始,把原来二进制的项目文件lgp改成Xml格式的文件llblgenproj。这是一个很重要的变化,
因为数据库属性最终映射的实体属性可以在设计器中修改,所以必须读取LLBL Gen Pro的项目文件才能确定最终映射的属性名称。 我的辅助开发工具中也依赖于llblgenproj项目文件的这个特性,在LLBL Gen Pro 2.x时代这是不可能的。
当时我的同事做了一个基于ORM的代码生成工具,用于生成实体接口与实现代码,解释如下:
数据库表SalesOrder –> 实体SalesOrderEntity -> 接口ISalesOrderManager –> 接口实现SalesOrderManager
后面两个步骤就是需要做的工作,同事设计的工具的原型如下:
有接近3年的时间,我都迷恋于这个工具产生的接口与实现类代码。直到后来有客户不断提出对接口与实现中细节的修改,我慢慢无法忍受用.NET代码写代码生成器,还要编译的苦恼。当时同事们都极力推荐模板生成技术,于是用Code Smith写下了模板代码,一直延续到今天。分享一下Code Smith生成接口的代码:
<%@ CodeTemplate Language="C#" TargetLanguage="C#" Src="" Inherits="" Debug="True" Description="Template description here." %>
<%@ Property Name="EntityPicker" Type="ISL.Extension.EntityPickerProperty" Optional="False" Category="Project" Description="This property uses a custom modal dialog editor." %>
<%@ Property Name="AssemblyFile" Type="System.String" Default="" Optional="False" Category="Project" Description=""
Editor="System.Windows.Forms.Design.FileNameEditor"%> <%@ Assembly Name="System.Data" %>
<%@ Import Namespace="System.Data" %>
<%@ Assembly Name="ISL.Empower.Extension" %>
<%@ Import Namespace="ISL.Extension" %>
<%@ Import Namespace="System.Collections.Generic" %>
<%@ Assembly Name="SD.LLBLGen.Pro.ORMSupportClasses.NET20" %>
<%@ Import Namespace="SD.LLBLGen.Pro.ORMSupportClasses" %> <script runat="template"> public string EntityName
{
get
{
return EntityPicker.EntityName;
}
} public string ShortEntityName
{
get
{
return EntityName.Substring(0,EntityName.Length-6);
}
} public string FullEntityName
{
get
{
return string.Format("{0}.EntityClasses.{1}", BusinessLogicProjectName, EntityName);
}
} private string _businessLogicProjectName; public string BusinessLogicProjectName
{
get
{
if(string.IsNullOrWhiteSpace(_businessLogicProjectName))
_businessLogicProjectName=EntityClassHelper.PrefixProjectName(AssemblyFile);
return _businessLogicProjectName;
}
} public string EntityParamerList
{
get
{
IEntity2 policy = EntityClassHelper.GetEntityObject(AssemblyFile, EntityPicker.EntityName);
string parm = string.Empty;
List<string> parms=new List<string>();
foreach (IEntityField2 field in policy.PrimaryKeyFields)
{
parm = string.Format("{0} {1}", field.DataType.Name, field.Name);
parms.Add(parm);
}
return string.Join(",", parms.ToArray());
}
} public string EntityLowercaseName
{
get
{
return EntityPicker.EntityName.Substring(0, 1).ToLower() + EntityPicker.EntityName.Substring(1);
}
} </script> using System;
using System.Collections.Generic;
using System.Data;
using System.Text;
using SD.LLBLGen.Pro.ORMSupportClasses; using <%=BusinessLogicProjectName%>;
using <%=BusinessLogicProjectName%>.FactoryClasses;
using <%=BusinessLogicProjectName%>.EntityClasses;
using <%=BusinessLogicProjectName%>.HelperClasses;
using <%=BusinessLogicProjectName%>.InterfaceClasses;
using <%=BusinessLogicProjectName%>.DatabaseSpecific; namespace <%=BusinessLogicProjectName%>.InterfaceClasses
{
public interface I<%=ShortEntityName%>Manager
{
<%=EntityName%> Get<%=ShortEntityName%>(Guid sessionId,<%=EntityParamerList %>);
<%=EntityName%> Get<%=ShortEntityName%>(Guid sessionId,<%=EntityParamerList %>,IPrefetchPath2 prefetchPath);
<%=EntityName%> Get<%=ShortEntityName%>(Guid sessionId,<%=EntityParamerList %>,IPrefetchPath2 prefetchPath,ExcludeIncludeFieldsList fieldList); EntityCollection Get<%=ShortEntityName%>Collection(Guid sessionId,IRelationPredicateBucket filterBucket);
EntityCollection Get<%=ShortEntityName%>Collection(Guid sessionId,IRelationPredicateBucket filterBucket,ISortExpression sortExpression);
EntityCollection Get<%=ShortEntityName%>Collection(Guid sessionId,IRelationPredicateBucket filterBucket,ISortExpression sortExpression, IPrefetchPath2 prefetchPath);
EntityCollection Get<%=ShortEntityName%>Collection(Guid sessionId,IRelationPredicateBucket filterBucket, ISortExpression sortExpression, IPrefetchPath2 prefetchPath, ExcludeIncludeFieldsList fieldList); <%=EntityName%> Save<%=ShortEntityName%>(Guid sessionId,<%=EntityName%> <%=EntityLowercaseName%>);
<%=EntityName%> Save<%=ShortEntityName%>(Guid sessionId,<%=EntityName%> <%=EntityLowercaseName%> ,EntityCollection entitiesToDelete);
<%=EntityName%> Save<%=ShortEntityName%>(Guid sessionId,<%=EntityName%> <%=EntityLowercaseName%>, EntityCollection entitiesToDelete, string seriesCode); void Delete<%=ShortEntityName%>(Guid sessionId,<%=EntityName%> <%=EntityLowercaseName%>); bool Is<%=ShortEntityName%>Exist(Guid sessionId,<%=EntityParamerList %>);
bool Is<%=ShortEntityName%>Exist(Guid sessionId,IRelationPredicateBucket filterBucket);
int Get<%=ShortEntityName%>Count(Guid sessionId,IRelationPredicateBucket filterBucket); <%=EntityName%> Clone<%=ShortEntityName%>(Guid sessionId,<%=EntityParamerList %>);
void Post<%=ShortEntityName%>(Guid sessionId,<%=EntityParamerList %>);
void Post<%=ShortEntityName%>(Guid sessionId,<%=EntityName%> <%=EntityLowercaseName%>);
}
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }再后来微软推出了T4模板代码生成工具,曾经有一段时间想把Code Smith转换成T4的模板,Code Smith 5.x不支持.NET3.5,一些.NET类库写的扩展方法,Code Smith模板不能用,这是想转成T4代码模板的原因。然而在网上找一个带智能提示,语法高亮的T4模板编辑器相当困难,在国外找到一个也是试用版,国内也没有破解版,再后来就没有完全没有动力去折腾了。Code Smith 6.x完全支持.NET 3.5,一直延续用到今天。
借助于LLBL Gen Pro,再加上以前积累的一些公共代码类库,一套原始的ERP系统成型,参考下面的视图:
这个项目中,抽象出了三个公共基类库,公共方法Common,公共控件WinUI,公共程序Core。后来硬盘丢失,实在找不到这个项目的源代码,不过设计思路与项目的架构已经了然于胸。
到2012年的时候,接触到Infragistics界面控件包,它几乎重写了整个WinForms的控件,提供的属性非常丰富。当时公司购买了这套控件的许可,可查看到控件的所有源代码。不过大部分时间都没有去看源代码,只有遇到不可理解的错误时,才会跟踪进入源代码查看参数传递是否合理正确。
有了实体和支持强类型对象的控件,这两者的结合,深远的影响了后来的程序设计生涯。虽然现有偶尔也会用DataTable,但大面积使用的开发模式仍旧是使用实体+数据绑定。
.NET数据绑定是需要深入学习的另一个领域,有了数据绑定,下面代码可以省略:
//Get value from control
string refNo=txtRefNo.Text; //set value to control
txtRefNo.Text="SO201507190001";
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
只需要将实体绑定给BindingSource控件,整个界面上的控件就全都有了值,不用上面的代码逐个赋值。
protected override void BindControls(EntityBase2 entity)
{
base.BindControls(entity); InventoryMovementEntity inventoryMovement = (InventoryMovementEntity)entity;
inventoryMovementBindingSource.DataSource = inventoryMovement;
}
对于WinForms开发,大量的取值和赋值操作代码都省略了,减少了代码,提高系统可维护性。
基本上到这里,我已经可以独立开发系统,系统的各个部件都可以处理好,我的开发步骤如下:
1 设计数据库表。找过很多case工具以辅助生成SQL Server数据表,最后还是回归SQL Server Management Studio,这是最好用的最简洁的工具,也方便与同事交流。当两个人用的数据库设计工具不同,而发生一些微小的错误或差异时,常常会令人抓狂。
2 LLBL Gen Pro生成实体,设置实体间关系。基本上就是连接到数据库,刷新实体,生成或更新实体文件。
3 生成实体读写的接口与实现类。借用Code Smith模板,效率高
4 拖拉界面,绑定数据源控件。即使没有学过编程,也可以经过短暂的培训快速上手开发界面。
5 给实体增加业务逻辑代码,界面与逻辑分离。这是要手写代码的地方,写业务逻辑,包含计算逻辑与验证逻辑。
接触LLBL Gen Pro 对象关系映射框架后 前途变的一片光明的更多相关文章
- Hibernate(开放源代码的对象关系映射框架)
Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自 ...
- android对象关系映射框架ormlite之一对多(OneToMany)
前两天,用ormlite对单张表进行了基本的操作,但是,我们知道通常情况对于单张表格进行操作在实际情况中很前两天不现实,那么ormlite能否像Hibenate那样实现多张表之间的一对多,多对多(即O ...
- Android数据库框架——GreenDao轻量级的对象关系映射框架,永久告别sqlite
Android数据库框架--GreenDao轻量级的对象关系映射框架,永久告别sqlite 前不久,我在写了ORMLite这个框架的博文 Android数据库框架--ORMLite轻量级的对象关系映射 ...
- JavaEE之Hibernate(开放源代码的对象关系映射框架)
Hibernate(开放源代码的对象关系映射框架) 1.简介 Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全 ...
- 解析大型.NET ERP系统数据访问 对象关系映射框架LLBL Gen Pro
LLBL Gen Pro是一个为.NET开发人员设计的的对象关系映射(ORM)框架,与NHibernate,Entity Framework等框架一样,通过实体与数据表的映射,实现关系数据库持久化. ...
- Hibernate (开源对象关系映射框架)
一.基本介绍1.它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm(对象关系映射)框架,hibernate可以自动生成SQL语句,自动执行: Hibern ...
- Enterprise Solution 3.1 企业应用开发框架 .NET ERP/CRM/MIS 开发框架,C/S架构,SQL Server + ORM(LLBL Gen Pro) + Infragistics WinForms
行业:基于数据库的制造行业管理软件,包含ERP.MRP.CRM.MIS.MES等企业管理软件 数据库平台:SQL Server 2005或以上 系统架构:C/S 开发技术 序号 领域 技术 1 数据库 ...
- ORM 对象关系映射
ORM (object relation mapping) 就是将对象数据转换为sql语句并执行 对象关系映射框架 orm 需要做的事情 1 生成创建表的语句 2 插入数据的语句 3 删除数据的语句 ...
- LLBL Gen Pro 4.2 Lite 免费的对象关系映射开发框架与工具
LLBL Gen Pro是一款优秀的对象关系映射开发框架,自2003年发布以来,一直有广泛的客户群.LLBL Gen Pro有几个标志性的版本,2.5/2.6是一个很稳定的版本,公司的一些旧的项目仍然 ...
随机推荐
- 【Android UI】Android开发之View的几种布局方式及实践
引言 通过前面两篇: Android 开发之旅:又见Hello World! Android 开发之旅:深入分析布局文件&又是“Hello World!” 我们对Android应用程序运行原理 ...
- 未能从程序集“System.ServiceModel, Version=3.0.0.0问题解决
在Windows Server 2008中的IIS服务器中部署WCF服务程序时,通过浏览器访问报出如下错误: 未能从程序集“System.ServiceModel, Version=3.0.0.0, ...
- Amazon Resource Names (ARNs)
The following are the general formats for ARNs; the specific components and values used depend on th ...
- [Leetcode]Reverse Integer
核心思想:原数对10取余数赋值给新数后降一位,再把新数升一位加上下一次原数取余值,直到原数降为0. 解法如下: int reverse(int x) { bool minus = false; ) ...
- [XAF] Keep the DetailView open in a popup window
public class ViewController1 : ViewController { ListViewProcessCurrentObjectController controller; p ...
- 基于AutoCAD的ObjectARX之NET扩展(mcnetarx)-AcdbEntNext、AcdbEntLast
1.AcdbEntLast用于获取最后一个创建的实体. 2.AcdbEntNext用于获取指定实体名称之后的下一个创建的实体. ' 定义保存实体名称的变量 Dim ent() As Integer = ...
- MYSQL删除表的记录后如何使ID从1开始
MYSQL删除表的记录后如何使ID从1开始 MYSQL删除表的记录后如何使ID从1开始 http://hi.baidu.com/289766516/blog/item/a3f85500556e2c09 ...
- 使用Inno Setup函数修改文件内容
0.inno打开文件操作&字符串操作所需函数原型及解释 function LoadStringsFromFile(const FileName: String; var S: TArrayOf ...
- 分享工作中遇到的问题积累经验 事务日志太大导致insert不进数据
分享工作中遇到的问题积累经验 事务日志太大导致insert不进数据 今天开发找我,说数据库insert不进数据,叫我看一下 他发了一个截图给我 然后我登录上服务器,发现了可疑的地方,而且这个数据库之前 ...
- 解剖SQLSERVER 第八篇 OrcaMDF 现在支持多数据文件的数据库(译)
解剖SQLSERVER 第八篇 OrcaMDF 现在支持多数据文件的数据库(译) http://improve.dk/orcamdf-now-supports-databases-with-mult ...