OQL如何支持CASE WHEN?
今天,一个朋友问我,OQL可否支持CASE WHEN语句?他给的示例SQL如下:
select HName,case when IsEnable=1 then '启用' else '停用' from tb_User
OQL是的,它类似Linq,但是它诞生的历史比Linq早,并且更加接近SQL语法。所以,对SOD框架而言,对应ORM如何支持CASE WHEN,就等于是问OQL如何支持CASE WHEN了。
这个问题已经不止这一个朋友来问我了,我想了下,还是把这个问题的解决写一篇博客,给大家一种新的解决方案。
注意“新的方案”这个提法,我是不打算让OQL支持CASE WHEN这个特性的,为何要这样做呢?- OQL只解决 80%的普通查询,其它复杂的查询,应该依托于其它技术,否则会增加OQL的复杂性;
- 复杂的查询,可以借助于SOD框架的,将SQL语句写在SqlMap.config文件中;
- 可以采用数据库视图或者表的计算列,但有些数据库可能不支持计算列;
实体类的计算属性
废话不多说,先直接看代码:
public class User:EntityBase{ public User() { TableName="tb_User"; } public string HName{ get{ return getProperty("HName");} set{setProperty ("HName",value,50);} } public bool IsEnable{ get{ return getProperty ("IsEnable");} set{setProperty ("IsEnable",value);} } public string IsEnableDescrition { get{ return IsEnable?"启用":"停用" } }}
在这里,HName,IsEnable 这样的属性,SOD框架称为“持久化属性”,因为它MAP了Tb_User表的字段IsEnable ,该字段称为“持久化属性字段”。
持久化属性的get,set方法采用了SOD实体类特殊的方法 setProperty,getProperty 构造,所以属性IsEnableDescription 它不是持久化属性,但是它利用了IsEnable这个持久化属性,对持久化属性进行“计算”,因此,我们这里称呼这样的属性为实体类的“计算属性”。
大家看看,这个“计算属性”是不是很好的起到了 SQL的CASE WHEN效果?
只要忘记了数据库,不要遇到问题就去想如何用SQL语句解决,是不是思路豁然开朗?
使用“计算属性”来支持CASE WHEN效果
前面说过,实体类的“计算属性”本质上不是一个“持久化属性”,它是对持久化属性的计算处理,原理上非常类似SQLServer表上面的计算列。
因此,在SOD框架上使用“计算属性”,有一个必须注意的原则:“计算属性”不可以出现在OQL语句中。具体举例来说,应该像下面的样子来使用包含计算列的实体类:
User user=new User(){ HName="张三"};var q=OQL.From(user) .Select(user.HName,user.IsEnable) .Where(user.HName).END;User user2= EntityQuery.QueryObject(q);string isEnableDesction =user2.isEnableDesction;
使用“ViewModel”来支持CASE WHEN效果
如果再仔细看看开篇的这个SQL语句,我们发现这种写法常常跟我们的界面查询有关,也就是这个查询要将原来的结果进行一下加工,以方便界面元素使用。对应这种需求,我们通常想到的办法是写一个ViewModel来定制这个查询结果。实际上,前面那个SOD实体类就是一种ViewModel,但它是基于实体类上的ViewModel,之外,SOD也支持直接将查询结果映射到ViewModel。因此,前面的实体类需要改写成下面这个样子:
public class User:EntityBase{ public User() { TableName="tb_User"; } public string HName{ get{ return getProperty("HName");} set{setProperty ("HName",value,50);} } public bool IsEnable{ get{ return getProperty ("IsEnable");} set{setProperty ("IsEnable",value);} } }
这里去掉了前面的“计算列属性”,它将用一个匿名类型的属性来代替:
User user=new User(){ HName="张三"};var q=OQL.From(user) .Select() .Where(user.HName).END; PWMIS.DataProvider.Data.AdoHelper db = PWMIS.DataProvider.Adapter.MyDB.GetDBHelper(); EntityContainer ec = new EntityContainer(q, db); var list = ec.MapToList()(()=> return new { HName = user.HName, IsEnableDescription =user.IsEnable?"启用":"停用" });
这里的匿名类型中包含了 IsEnableDescription 一个属性,同时我们的OQL查询也不再需要在Select里面指定查询的属性,而是推迟到MapToList方法里面。
上面这种查询方式,同样支持了我们标题的需求,可见,SOD对一个查询问题,往往能够提供多种解决方案,“条条道路通罗马”,这正是SOD的设计谏言。
---------------分界线--------------------------------------------------------------------------------
有关上面SOD框架查询使用的入门介绍,大家可以参考
感谢大家对SOD框架一直以来的支持,更多信息,请参考
开源项目需要大家更多的支持,SOD开源项目网站: