问题:3行代码

PDF.NET是一个开源的数据开发框架,它的特点是简单、轻量、快速,易上手,而且是一个注释完善的国产开发框架,受到不少朋友的欢迎,也在我们公司的项目中多次使用。但是,PDF.NET比起EF来,仍然有很大的劣势,主要就是用起来没有EF简单,这个问题饱受广大朋友的批评,但我很感谢这些朋友,他们的批评才是框架进步的动力,为此,之前我发表了《来一点反射和Emit,让ORM的使用极度简化》  这篇文章,使得不再需要定义实体类,只需要有接口即可访问数据库

原文的代码:

    static void TestDynamicEntity()
{
ITable_User user = EntityBuilder.CreateEntity<ITable_User>();
//如果接口的名称不是"ITableName" 这样的格式,那么需要调用 MapNewTableName方法指定
//((EntityBase)user).MapNewTableName("Table_User"); OQL qUser = OQL.From((EntityBase)user).Select(user.UID, user.Name, user.Sex).END;
List<ITable_User> users = EntityQuery.QueryList<ITable_User>(qUser, MyDB.Instance);
}

这段程序花了3行代码来做一个查询,还是有点繁琐。如果不是这种接口类型的动态实体类,可以通过下面的扩展方法来简化查询:

 public static List<T> ToList<T>(this OQL q) where T:EntityBase,new()
{
return EntityQuery<T>.QueryList(q);
} public static OQL From<T>() where T : EntityBase, new()
{
T entity = new T();
return OQL.From(entity);
}

有了这2个“扩展”方法,我们的查询可以一行完成了:

 List<User> users=OQL.From<User>.ToList<User>();

等同于

 List<User> users=OQL.From<User>.Select().END.ToList<User>();

但这样的写法没法选择需要的列,如果要附加查询条件,在V5.0之前,还得这样做:

 User user=new User(){UserName="zhangsan",Password="abc."}
List<User> users=OQL.From(user)
.Select(user.ID,user.UserName,user.Password)
.Where(user.UserName,user.Password)
.END
.ToList<User>();

这样查询还得需要2行代码,而且没有利用上泛型的优势,最后的ToList还得指定类型User ,这样写仍然不优雅。

曙光:V5版本

PDF.NET Ver 5.0 在经过了脱胎换骨般的重构后,OQL增加了大量特性,OQL方法支持Lambda表达式语法,支持泛型,我们前面的代码有望得到简化:

Users user = new Users();
var userList = OQL.From(user)
.Select(user.UserName, user.ID)
.Where<Users>((cmp,u)=>cmp.Compare(u.ID,">",)
//.OrderBy(p => p.Desc(user.UserName).Asc(user.ID)) //2种排序方式
.OrderBy<Users>((o,u) => { o.Desc(u.UserName); })
.END
.ToList<Users>();

OQL V5.0.0的写法还得借助Users 的对象实例来选取字段,或者动态排序,仍然多了一行代码:

Users user = new Users();

这一行代码尽管能够给我在Where条件相等比较上代来便利,直接将条件值传入进去,但不管怎么说,一个查询还是让我多写了一行代码,没有做到EF那样,一行代码解决问题。这多出来的一行代码,让PDF.NET的用户朋友很不满意的,主要就是,EF都可以一行查询出来,PDF.NET为什么不行?太麻烦了!

我常常在想,为什么“客户”这么难以伺候,就多写了一行实体类的实例化的代码,这都显得麻烦么?还有各种好处呢,PDF.NET基于实体类的实例调用特性,构筑起了OQL支持复杂查询的特性(参见 《ORM查询语言(OQL)简介--高级篇(续):庐山真貌》 ),SQL能够支持的,OQL基本上都能够支持了。

但是,我说的好处似乎很难让我的“客户”朋友门满意,还是那句话:

EF都可以做到,PDF.NET为什么做不到?

我的理想是,EF可以做到的,PDF.NET 也尽量做到,EF做不到的,PDF.NET 要做到!

否则,在众多ORM框架的围攻下,PDF.NET很难生存下去。EF都开源了,说明做ORM竞争太激烈了,没有特色,更本没法生存。

在考虑了几天之后,我认为基于现在PDF.NET V5.0的新版核心,有可能真正实现一行代码进行数据查询的。
  问题所在也很清楚了,就是那个实体类的申明语句让我很尴尬:

Users user = new Users();

只要干掉它,我就成功了!
    而这,完全可以在下面的方法中做“手脚”实现:

 public static OQL From<T>() where T : EntityBase,new()
{
T entity=new T(); return new OQL(entity);
}

很简单嘛,这样就可以一行代码实现查询了:

var userList = OQL.From<Users>()
.Select()
.Where<Users>((cmp,u)=>cmp.Compare(u.ID,">",)
.OrderBy<Users>((o,u) => { o.Desc(u.UserName); })
.END
.ToList<Users>();

目的达到了,原来只要肯想法,办法还是很简单的,心中一阵窃喜:)

精简:让用户再懒一点

过了一会儿,再反复看看上面这一行代码,发现了几个问题:

  1. Select 方法没法指定要选择的表字段;
  2. Where,OrderBy,ToList 都需要指定泛型的具体类型,既然From<Users> 最开始已经指定过了,那么后面的方法再指定<Users>就有点冗余。

为了让框架的“客户”再少敲几个字符,我决定构造一个OQL的泛型类,这样它相关的操作方法就不需要反复制定具体类型了,同时想法解决问题1。于是,这个新类如下定义:

public class GOQL<T> where T:class
{
protected internal OQL currentOQL;
private T currentEntity;
public delegate object[] SelectFieldFunc(T s); public GOQL1<T> Select(SelectFieldFunc func)
{
return new GOQL1<T>(this, currentOQL.Select(func(currentEntity)));
}
/* 其它方法略 */
}

有了SelectFieldFunc 这个委托,就可以给Select 方法使用了,选择指定的字段数据:

currentOQL.Select(func(currentEntity))

接下来,按照OQL的设计思路,进行SQL 语句分层 设计,目前只打算支持Where 和OrderBy字句,所以需要定义下面的子类:

public class GOQL1<T> : GOQL2<T> where T : class
{
public GOQL2<T> Where(OQLCompareFunc<T> func)
{}
} public class GOQL2<T> where T : class
{
public GOQL<T> OrderBy(OQLOrderAction<T> orderAct)
{}
}

由于SQL语句不一定需要Where子句,可以直接在 Select 子句后跟Order By 子句,所以让GOQL1<T>继承 GOQL2<T> 。

OK,经过这样的设计,整个GOQL代码只有95行代码,没错,只有95行,目前还没有写注释,详细代码请展开看下面的内容:

 using System;
using System.Collections.Generic;
using PWMIS.DataProvider.Data;
using PWMIS.DataProvider.Adapter; namespace PWMIS.DataMap.Entity
{
public class GOQL<T> where T:class
{
protected internal OQL currentOQL;
private T currentEntity;
public delegate object[] SelectFieldFunc(T s); public GOQL(OQL oql,T entity)
{
this.currentOQL = oql;
this.currentEntity = entity;
}
public GOQL1<T> Select()
{
return new GOQL1<T>(this, currentOQL.Select());
}
public GOQL1<T> Select(SelectFieldFunc func)
{
return new GOQL1<T>(this, currentOQL.Select(func(currentEntity)));
}
public GOQL<T> Limit(int pageSize, int pageNumber)
{
this.currentOQL.Limit(pageSize, pageNumber);
return this;
}
public GOQL<T> Print(out string sqlInfo)
{
sqlInfo = string.Format("SQL:{0}\r\n{1}",currentOQL.ToString(), currentOQL.PrintParameterInfo());
return this;
}
public List<T> ToList(AdoHelper db )
{
return EntityQuery.QueryList<T>(this.currentOQL, db);
}
public List<T> ToList()
{
return ToList(MyDB.Instance);
}
public T ToObject(AdoHelper db)
{
return EntityQuery.QueryObject<T>(this.currentOQL, db);
}
public T ToObject()
{
return ToObject(MyDB.Instance);
}
public override string ToString()
{
return currentOQL.ToString();
}
} public class GOQL1<T> : GOQL2<T> where T : class
{
private GOQL<T> currentGOQL;
private OQL1 currentOQL1; public GOQL1(GOQL<T> gq,OQL1 q1):base(gq)
{
this.currentGOQL = gq;
this.currentOQL1 = q1;
} public GOQL2<T> Where(OQLCompareFunc<T> func)
{
this.currentOQL1.Where(func);
return new GOQL2<T>(currentGOQL);
}
} public class GOQL2<T> where T : class
{
private GOQL<T> currentGOQL; public GOQL2(GOQL<T> gq)
{
this.currentGOQL = gq;
}
public GOQL<T> OrderBy(OQLOrderAction<T> orderAct)
{
OQL4 currentOQL4 = new OQL4(this.currentGOQL.currentOQL).OrderBy<T>(orderAct);
return this.currentGOQL;
}
public GOQL<T> END
{
get { return this.currentGOQL; }
}
}
}

--GOQL详细代码--

成功:一行代码的真相

为了让大家更清楚GOQL的结构和它与PDF.NET框架其它部分的关系,请看下面的类图:

-类图-

最后,我们就可以写一个真正的测试代码了:
  95行源码,一行代码调用实现带字段选取+条件判断+排序+分页功能的增强ORM框架

static void TestGOQL()
{
string sqlInfo="";
//下面使用 ITable_User 或者 Table_User均可
List<ITable_User> userList =
OQL.FromObject<ITable_User>()
//.Select()
.Select(s => new object[] { s.UID, s.Name, s.Sex }) //仅选取3个字段
.Where((cmp, user) => cmp.Property(user.UID) < )
.OrderBy((o,user)=>o.Asc(user.UID))
.Limit(, ) //限制5条记录每页,取第一页
.Print(out sqlInfo)
.ToList(); Console.WriteLine(sqlInfo);
Console.WriteLine("User List item count:{0}",userList.Count);
}

这次新增了 OQL.FromObject<T>() 方法,类型T即可以是一个普通接口,也可以是一个PDF.NET的实体类

有图有真相,下面是这个测试程序的输出截图:

-截图-

收工,PDF.NET 顺利实现一行代码查询数据的功能,除了Where 条件的复杂写法不那么优美,总体上GOQL,OQL可以媲美EF了!

注意:GOQL功能,在PDF.NET框架的Ver 5.0.1 版本支持,之前的https://pwmis.codeplex.com/releases/view/104043 PDF.NET_V5.0Beta_20130807 不支持,要获取框架的最新源码,请加入本框架的官方QQ群,详细联系信息请看框架官网 http://www.pwmis.com/sqlmap

最后总结下PDF.NET ORM 各个类的使用场景:

  • GOQL :解决单实体类的R(Read);
  • OQL+EntityQuery<T>: 解决单实体类的CRUD;
  • OQL+EntityContainer: 解决多实体类的R

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

感谢广大PDF.NET的会员和用户朋友一直以来的支持,你的批评是我们进步的力量!欢迎加入框架的开源项目

一行代码调用实现带字段选取+条件判断+排序+分页功能的增强ORM框架的更多相关文章

  1. 一次项目代码重构-使用spring容器干掉条件判断

    一次项目代码重构-使用spring容器干掉条件判断 这是在一次公司项目中进行重构时,一些复杂业务时想到的一个去掉一些if else的办法.能够使代码逻辑更加清晰,减少一些业务上的耦合. 业务说明 我所 ...

  2. MySQL的选则字段+联表+判断+排序(order by)

    MySQL的选则字段+联表+判断+排序(order by) 两个表:1.成绩单 2.查询名单 目标: 1.选中全部字段,用于输出. 2.成绩单中有很多人的成绩,第一步是希望通过联表,只查查询名单上的人 ...

  3. PyTorch Hub发布!一行代码调用最潮模型,图灵奖得主强推

    为了调用各种经典机器学习模型,今后你不必重复造轮子了. 刚刚,Facebook宣布推出PyTorch Hub,一个包含计算机视觉.自然语言处理领域的诸多经典模型的聚合中心,让你调用起来更方便. 有多方 ...

  4. Spring Boot Jpa 多条件查询+排序+分页

    事情有点多,于是快一个月没写东西了,今天补上上次说的. JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将 ...

  5. PHP连接数据库实现多条件查询与分页功能——关于租房页面的完整实例操作

    租房页面如图: 代码如下: <!DOCTYPE html><html>    <head>        <meta charset="UTF-8& ...

  6. CodeIgniter框架多条件搜索查询分页功能解决方案

    最近在用ci框架写功能的时候,需要用到分页功能,本来寻常的数据结果分页是比较简单的,但是这次写的功能是多条件搜索查询分页,就有点难度了,看官方手册下面评论好多人问, 正常的分页功能例子是这样的: $t ...

  7. 使用正则表达式获取Sql查询语句各项(表名、字段、条件、排序)

    string text = "select * from [admin] where aa=1 and cc='b' order by aa desc "; Regex reg = ...

  8. 初识sa-token,一行代码搞定登录授权!

    前言 在java的世界里,有很多优秀的权限认证框架,如Apache Shiro.Spring Security 等等.这些框架背景强大,历史悠久,其生态也比较齐全. 但同时这些框架也并非十分完美,在前 ...

  9. JAVA条件判断

    一.基本if结构 1.流程图 l  输入输出 l  判断和分支 l  流程线 1.1              简单的if条件判断 if(表达式){            //表达式为true,执行{ ...

随机推荐

  1. 复杂 XML 的 序列化 反序列化

    已知.xml(再此命名default.xml)文件,请将其反序列化到一个实例对象. <?xml version="1.0" encoding="utf-8" ...

  2. C# 开发2048小游戏

    这应该是几个月前,闲的手痒,敲了一上午代码搞出来的,随之就把它丢弃了,当时让别人玩过,提过几条更改建议,但是时至今日,我也没有进行过优化和更改(本人只会作案,不会收场,嘎嘎),下面的建议要给代码爱好的 ...

  3. Android开发之时间日期1

     对于手机的时间日期设置估计大家一定都不陌生吧,今天做了一个关于时间日期设置的小例子,其中遇到一个问题,求指导,如何使设置的时间日期和手机系统同步?还望高手指点一二. 先不说这个了,分享一下我的小例子 ...

  4. javase基础复习攻略《九》

    本篇将为大家总结JAVA中的线程机制,谈到线程,大家一定会问线程和进程有什么区别?刚接触进程时我也有这样的疑问,今天就为大家简单介绍一下进程和线程.进程(Process)是计算机中的程序关于某数据集合 ...

  5. Yii2的深入学习--入口文件

    前一段时间,尝试去写一个 php 的简单框架,发现自己还欠缺很多,就暂时停掉了.准备先读完 Yii2 的源码,然后再去看完 laravel 的源码,最后再继续去写这个简单的 php 框架. 之后关于 ...

  6. (原创)详解KMP算法

    KMP算法应该是每一本<数据结构>书都会讲的,算是知名度最高的算法之一了,但很可惜,我大二那年压根就没看懂过~~~ 之后也在很多地方也都经常看到讲解KMP算法的文章,看久了好像也知道是怎么 ...

  7. 漫谈可视化Prefuse(五)---一款属于我自己的可视化工具

    伴随着前期的基础积累,翻过API,读过一些Demo,总觉得自己已经摸透了Prefuse,小打小闹似乎已经无法满足内心膨胀的自己.还记得儿时看的<武状元苏乞儿>中降龙十八掌最后一张居然是空白 ...

  8. MVC导出数据到EXCEL新方法:将视图或分部视图转换为HTML后再直接返回FileResult

    导出EXCEL方法总结 MVC导出数据到EXCEL的方法有很多种,常见的是: 1.采用EXCEL COM组件来动态生成XLS文件并保存到服务器上,然后转到该文件存放路径即可: 优点:可设置丰富的EXC ...

  9. IOS从视频中获取截图

    从视频中获取截图: NSString *movpath =[[NSBundle mainBundle] pathForResource:@”iosxcode4″ ofType:@”mov”]; mpv ...

  10. ASP.NET MVC初识

    最近在博客园看到了很多关于MVC的示例,自己打算写下来记录一下,如果有写得不对的地方,望大侠指出! 开始搭建项目 1. 建立Web项目 文件—>新建项目—>选择ASP.NET MVC4 W ...