thought persistence

简单,再简单一点

博客园 首页 新随笔 联系 订阅 管理
  15 Posts :: 0 Stories :: 142 Comments :: 1 Trackbacks

2007年9月2日 #

     摘要: 方法名称为"As" 会导致整个IDE崩溃  阅读全文
posted @ 2007-09-02 16:31 progame 阅读(331) | 评论 (3)编辑

2007年8月28日 #

     摘要: XENOCODE使用中的一些心得  阅读全文
posted @ 2007-08-28 13:20 progame 阅读(2958) | 评论 (3)编辑

2007年7月29日 #

     摘要: 既然是ORM的测试, 就得体现这么几点:
one-one, many-ony, many-many关系
typed query 类型化查询
entity crud 实体的crud
traverse entity list 实体集合的构造和遍历  阅读全文
posted @ 2007-07-29 17:33 progame 阅读(2133) | 评论 (3)编辑

2007年7月26日 #

     摘要: 希望ORM性能测试的例子能够更好地反映实际运用情况  阅读全文
posted @ 2007-07-26 09:49 progame 阅读(2375) | 评论 (19)编辑

2007年7月3日 #

     摘要: 一直以来, 大家热衷于存储过程分页谁分得快, 但是我们搜索一下"通用分页存储过程", 就会发现这个有问题的方法流传得颇广  阅读全文
posted @ 2007-07-03 21:44 progame 阅读(2664) | 评论 (17)编辑

2005年1月26日 #

令人心动的对象化查询

对象化查询是O/R Mapping中非常让人心动的一个特性,当所有的表对我们来说不复存在后,我们可以对实体进行CRUD,可是当我们需要返回多个实体的结果集时,我们怎么办呢?Dataset做为载体是必然的,可是我们查询过滤数据的方式是怎样的?sqlNo!我们就是在尽量避免直接使用sql,因为sql不便于重构,可移植性太差,拼凑出来的sql语句对测试覆盖率也有影响。所以大家都期待着可以用对象化查询来根除将Entity再当做Table来处理的尴尬。

 

.Net下的O/R Mapper对对象化查询的支持

目前为止,.Net下的O/R Mapper对对象化查询的支持绝大部分都是非常有限的:NHibernate用的是HQL语句,其本质可以说是一种把Entity看做Table的改装后的sql语句,DataObjects.NetNHibernate差不多,也有一套自己的类sql对象化查询语法,其它很多O/R Mapper使用的是简单的属性过滤查询,而说到对对象化查询支持得最强大的,要算ECOⅡ和ObjectSpaces,前者使用的是OCL语法,后者是OPath

 

OCL起源

OCLOMG组织制订的UML语言规范的一部分,它的初衷是用来对UML模型视图中的Object添加约束描述的,并不是一种编程语言,而OCL应用到O/R Mapping中就俨然成了一种对对象进行查询的语言(OQL)。

 

OPath起源

OPathMS提出的在WinFS中准备大量使用的一种对象查询语言,从它的命名上可以看出和XPath的相似之处,MS的口号一直是把复杂的东西变简单,把简单的东西变成自动化。所以这个OPath确实不可小觑。

 

简单的例子

先我们从一个简单的例子入手,假设有如下的实体关系(画图太麻烦,还浪费空间):

Department (code name employees)

Employee(code name department salary)

查询

OCL

OPath

包含薪水大于3000的员工所有部门

Department.allInstances->select(self.employees.includes(salary > 3000))

Exists(employees[saleary > 3000])

得到部门001的所有员工

Employee.allInstances->select(self.department.code = ‘001’)

Department.code = ‘001’

所有员工薪水都大于3000的部门

Department.allInstances->select(self.employees.forAll(salary > 3000))

不支持

员工最高薪水大于3000的部门

Department.allInstances->select(self.employees.includes(salary > 3000))

不支持

 

功能比较

从这个列表中可以看到OPath的语法要简洁得多,但OCL的集合操纵能力却是OPath无法比拟的,下面是OCL的一些集合函数:

名称

功能

Collect

得到一个属性的集合

Exists

如果存在符合条件的元素为真

forAll

只有所有集合元素符合条件时才为真

Includes

是否包含某个对象

Select

获取符合条件的一个子集

Reject

减去符合条件的一个子集

IsEmpty

集合为空

NotEmpty

集合不为空 

此外,ECOⅡ对集合操作还有增强,如提供了sumavgmaxmin的聚集操作函数,同时它还支持多种非聚集函数,如concatlengthtouppertolower等。

 

其它的一些特性:

特性

OCL

OPath

NULL判断

支持

支持

Implies(表示如果左边为真,那么右边也要为真)

支持

A implies B可以转化为(A and B) or (Not A)

类型判断和转换

支持

Distinct

支持(通过Set集合返回)

不支持(因为只是对象获取和属性过滤,没有集合操作,所以不涉及到子集合,而外部对象集合一般有主键约束)

集合内元素获取

支持

不支持

Order By

支持

不支持,但可以通过调用查询对象的方法达到目的

 

假如增强OPath的话,大概会是什么样子?

如果要支持集合操作的话,那么现有的OPath语法的简单性肯定要大打折扣,比如说类似于OCL中的forAllOPath如果要实现的话,可能的方法就是:

(Employees[salary > 3000].Count = Employees.Count)

 

性能比较

因为现在ObjectSpaces中的OPath语句最后都将转为SQL执行,所以它的性能是非常好的(时这也正是它功能无法强大的弱点),而OCL的语法只有部分才能转化为SQL,因此在ECOⅡ中,还有部门的OCL操作必须针对内存对象来进行,这样也就使得必须装载大量的实体对象到内存中。

 

你将选择哪种查询?

就我个人而言,我倾向于增强型的OPath。毕竟更加复杂的查询我们可以通过viewstore procedure来完成,就算OCL再强大,也无法涵盖我们需要的查询功能,其内存对象操纵的性能问题不能不让我们谨慎使用,而ECOⅡ可以算是一个MDA的框架,这也让我对MDA的将来感到一些担忧,除非ANSI SQL进化到了可以更加强大的地步,各数据库本身就可以完成OCL所需要的查询功能,但这个时候,也许SQL的表达更加直观,那么,我们又为什么需要OCL来查询呢。当然,OCLUML中的作用我们并不否定,只是直接从模型生成代码的应用似乎只能在不太复杂的场合才生效。

 

(注:因为ECOⅡ的资料很少,很多是参考它的前身bold for delphi的语法,而OPath的资料也少,很多都是无关痛痒的简单操作,这让人弄不明白到底是它的语法就这么简单还是另有其它的增强。)

posted @ 2005-01-26 10:50 progame 阅读(1987) | 评论 (4)编辑

2005年1月14日 #

先建立一个简单的表结构

create table test (a int ,b datetime)
create index idx_b on test(b)

再来点测试数据

declare @i int
declare @x int
set @i = 0
set @x = 0
while (@i < 1000)
begin
insert into test values(@i,dateadd(hour,rand(@x)* 10000,getdate()))
set @x = @x + rand()* 1000
set @i = @i + 1
end


这样两句查询:

select a from test
select 1 from test

可以看到前者使用全表扫描,后者使用了索引,这样一来实在是很迷惑,SQLSERVER为什么要对后者使用索引扫描呢?又没有过滤条件。

其实是有原因的,因为SqlServer知道后者不会取表数据,那么对于索引树的扫描将要快于表的扫描(其实事实上未必如此),因为索引树占用空间一般是要小于表数据空间的,而小的数据读取可以减小I/O读取,要知道这是最耗时的一个操作,但实际上呢,因为当前索引使用的是占数据行空间绝大多数的b字段,所以在这里,第二条语句是要慢于第一条的。

如果不信,那么继续,先对表加一个a字段的非聚集索引:

create index idx_a on test(a)

然后再执行上面两个查询,这次SQLSERVER很聪明地选择了占用空间更小的idx_a索引扫描来对第二句查询进行执行,但是等等,怎么还是第一个查询执行得更快??? 其实原因很简单,对索引树的遍历比对表空间的遍历是更复杂的,因为索引树居然有中间节点来存放数据(大家看看B树的结构就明白了,SQLSERVER使用的是B-树),只有叶子节点才指向的是具体的数据(这个指向会因为有没有聚集索引而不同,这个以后会讲到),因此第一句的全表扫描要快一些,这是不是表示SQLSERVER选择了错误的扫描方式呢?非也,现在试着把数据加大到10000条,再执行,看到了吧,索引扫描是要快的(此处忽略对字段a的select操作成本,因为此成本开销实在是非常小的)。

再来执行两条SQL语句:

select * from test where b is null
select * from test where b is not null

可以看到,这两个查询都利用了索引,在此更正我上一篇BLOG中的错误,SQLSERVER是会将NULL值存入索引树的,这和它的数据结构有关,通过NULL位图,它可以处理NULL值,而索引叶子节点中的数据存放结构和表数据行的结构是大同小异的,而Oracle是不会存放NULL到索引的。

好了,先吃饭了,接下来的东西以后再讲。
posted @ 2005-01-14 11:40 progame 阅读(1332) | 评论 (3)编辑

2005年1月12日 #

  数据库定义到char类型的字段时,不知道大家是否会犹豫一下,到底选char、nchar、varchar、nvarchar、text、ntext中哪一种呢?结果很可能是两种,一种是节俭人士的选择:最好是用定长的,感觉比变长能省些空间,而且处理起来会快些,无法定长只好选用定长,并且将长度设置尽可能地小;另一种是则是觉得无所谓,尽量用可变类型的,长度尽量放大些

  鉴于现在硬件像萝卜一样便宜的大好形势,纠缠这样的小问题实在是没多大意义,不过如果不弄清它,总觉得对不起劳累过度的CPU和硬盘。

下面开始了(以下说明只针对SqlServer有效):

1、当使用非unicode时慎用以下这种查询:
            select f from t where f = N'xx'

    原因:无法利用到索引,因为数据库会将f先转换到unicode再和N'xx'比较

2、char 和相同长度的varchar处理速度差不多(后面还有说明)

3、varchar的长度不会影响处理速度!!!(看后面解释)

4、索引中列总长度最多支持总为900字节,所以长度大于900的varchar、char和大于450的nvarchar,nchar将无法创建索引

5、text、ntext上是无法创建索引的

6、O/R Mapping中对应实体的属性类型一般是以string居多,用char[]的非常少,所以如果按mapping的合理性来说,可变长度的类型更加吻合

7、一般基础资料表中的name在实际查询中基本上全部是使用like '%xx%'这种方式,而这种方式是无法利用索引的,所以如果对于此种字段,索引建了也白建

8、其它一些像remark的字段则是根本不需要查询的,所以不需要索引

9、varchar的存放和string是一样原理的,即length {block}这种方式,所以varchar的长度和它实际占用空间是无关的

10、对于固定长度的字段,是需要额外空间来存放NULL标识的,所以如果一个char字段中出现非常多的NULL,那么很不幸,你的占用空间比没有NULL的大(但这个大并不是大太多,因为NULL标识是用bit存放的,可是如果你一行中只有你一个NULL需要标识,那么你就白白浪费1byte空间了,罪过罪过!),这时候,你可以使用特殊标识来存放,如:'NV'

11、同上,所以对于这种NULL查询,索引是无法生效的,假如你使用了NULL标识替代的话,那么恭喜你,你可以利用到索引了

12、char和varchar的比较成本是一样的,现在关键就看它们的索引查找的成本了,因为查找策略都一样,因此应该比较谁占用空间小。在存放相同数量的字符情况下,如果数量小,那么char占用长度是小于varchar的,但如果数量稍大,则varchar完全可能小于char,而且要看实际填充数值的充实度,比如说varchar(3)和char(3),那么理论上应该是char快了,但如果是char(10)和varchar(10),充实度只有30%的情况下,理论上就应该是varchar快了。因为varchar需要额外空间存放块长度,所以只要length(1-fillfactor)大于这个存放空间(好像是2字节),那么它就会比相同长度的char快了。

13、nvarchar比varchar要慢上一些,而且对于非unicode字符它会占用双倍的空间,那么这么一种类型推出来是为什么呢?对,就是为了国际化,对于unicode类型的数据,排序规则对它们是不起作用的,而非unicode字符在处理不同语言的数据时,必须指定排序规则才能正常工作,所以n类型就这么一点好处。


总结陈词:
1、如果数据量非常大,又能100%确定长度且保存只是ansi字符,那么char
2、能确定长度又不一定是ansi字符或者,那么用nchar;
3、不确定长度,要查询且希望利用索引的话,用nvarchar类型吧,将它们设到400;
4、不查询的话没什么好说的,用nvarchar(4000)
5、性格豪爽的可以只用3和4,偶尔用用1,毕竟这是一种额外说明,等于告诉别人说,我一定需要长度为X位的数据

这样一来,生活是不是变成美好多了? 如果还有没明白的,那么还是省点钱去买萝卜吧。

posted @ 2005-01-12 00:03 progame 阅读(3665) | 评论 (9)编辑

2004年12月26日 #

  功夫看了枪版(为自己汗颜一下,实在是等不及了,而电影院多少年没有进去了已经),然后开始在网上找相关评论,就好像是自己的东西一样,期待着人们有好的反应,结果大家也知道,毁誉参半,或者说批评还要多一些,说星爷放弃了擅长的无厘头,玩起来了特效,失去了自我。

  Persistore是什么? 一个我正在开发的for .Net的O/R Mapping框架,大家可能奇怪了,现在成熟半成熟的.Net下的O/RM都已经多得让人眼花缭乱了,为什么还要自己开发一个?! 难道我这么喜欢无意义的重复开发,并且想依靠这个东西来证明自己的能力?

  再回到功夫上来,可以说,我一向欣赏的是香港电影讲故事的能力和星爷无厘头的表演,对于国产大片(以英雄、埋伏为代表)和好莱坞大片却并不感冒,因为我需要的不是视觉的冲击而是看电影时的放松和快乐,哈哈一笑,仅此而已,然而功夫在这方面带给我的这些东西非常少,可以说让我很“失望”,但是同时我们应该知道,功夫是星爷的再一次尝试,为了圆一个儿时的梦,用三年时间,换来一部风格迥异的电影,当然他自然也会从票房着想,为了国际化,更多地简化语言,强调动作。

  我不喜欢功夫,但是我欣赏星爷的这种尝试和努力,同时Persistore也是我自己的尝试和努力,因为我一直以来就想开发我所希望的O/RM,.Net出现已经4年了,而我现在才正式开始进入.Net开发,然而我这个想法一直以来就没有改变过。

  那么Persistore有哪些特性?它凭什么可以让我不选择其它的成熟解决方案?就像黑客帝国、指环王中的特效已经这么好了,为什么功夫还要玩特效?

1、纯实体类
  这是我对自己的O/RM最重要的一个要求,纯实体类不仅轻,而且可以便于移植(有人说了,谁会去移植?!),可能是我太偏执的原因吧。

2、自动映射
  Persistore不需要自定义属性和XML文件的支持便可实现映射。 我们已经有了数据库模型了,我们已经有了实体类了,为什么还需要再去维护映射?!

3、关系维护
  OnetoOne、OnetoMany、ManytoMany、SelfAssociate支持,正如yyanghhong所说,不支持关系的O/RM还不如直接用typed-dataset.

4、自动创建数据库结构(需要自定义属性支持)
  Class->Database已经成为潮流了,本来不准备支持的,但同事AdamBear说得很对,在早期的迭代式开发中,难以建立完整的数据库模型,所以实体类是优先考虑的。和其它框架不一样的是,Persistore不需要创建额外的字典信息表,同时可以在主键不改变的情况下动态添加、删除、更新字段的定义。

5、lazy-loading
  在支持关系维护后,没有迟加载的话,那么对于性能就是致命的下降。Persistore可以迟加载对象属性、实体集合,并且对于迟加载的实体集合只使用一次查询完成。

6、实体继承
  Persistore完全支持实体继承,可以同时支持JoinTable和UnionTable两种持久化方案,即分表保存和单表保存。

7、对象化查询
  现有的O/RM中只有极少数的(如ECO)支持真正的对象化查询(即UML2.0中的OCL),hibernate的HQL实际上还是sql的变种,Dataobjects.Net里的也还是sql,不过比sql还难理解,Persistore的OCL支持同样也是有限的(扩充了函数,但减弱了集合操作,因为OCL最终将解析成SQL),它的形式如下:

    Department.Employees->Sum(salary) > 100

  重要的是对关系的查询,而不仅仅是属性的过滤。

8、跨数据库平台和SqlBroker

  从一开始,Persistore的设计就是要支持多数据库平台的,各大数据库厂商对标准SQL的支持越来越好,同时标准SQL本身的功能也在增强,这使得平台无关的SQL语句已经可以完成绝大多数功能。通过Persistore执行的sql只能是被其支持的标准SQL。

9、View、Store Procedure支持
  这是一个数据库应用程序必不可少的,同时弥补上面SqlBroker的不足。

10、其它特性
  Criteria查询构造、NULL处理、事务支持(transaction和savepoint)、不完全实体对象查询、多种"脏"标志获取方法(default value、snapshot value、dynamic proxy)、延迟更新和批量更新。。。


还需要多久?

  目前差的是OCL和ANSISQL的解析(语法分析已经完成)、Store Procedure的封装以及最重要的实体类自动生成工具(CodeDG已经够灵活了,但它还不能提供Persistore最需要的外键约束信息)

如何使用?

  一个简单的例子:

 Session s = new Session(DB.CONNECTSTRING);

 Address a1 
= new Address();

 a1.id 
= "001";
 a1.street 
= "any";

 Class c1 
= new Class();

 c1.id 
= "01";
 c1.name 
= "grade1";
 
 Student s1 
= new Student();

 s1.Class 
= c1;
 s1.address 
= a1;
 s1.id 
= "0001";
 s1.name 
= "progame";
 
 Assert.IsTrue(s.Save(s1));

 Student s2 
= (Student)s.Load(typeof(Student), "0001");
 Assert.AreEqual(s1.name, s2.name);
 Assert.AreEqual(s1.Class.name, s2.Class.name);
 Assert.AreEqual(s1.address.street, a1.street);

 Student s3 
= new Student();
 s3.id 
= "0001";
 s.Load(s3);


  
最后说点什么

  写代码真的好累,有时候真的不想写了,但想想星爷,想想功夫,即使做出一个被人批评的东西,但至少事后我可以无悔地说:我做过了!
  

  

posted @ 2004-12-26 16:27 progame 阅读(1914) | 评论 (24)编辑

2004年12月6日 #

  今天,特意去看了下Comega,其它的特性暂时都略过,只是看它的语言对sql的直接集成,只能说是震惊!!! 先不说它的sql语法特性支持是否强大,因为这些是可以慢慢增强的,我最欣赏的是它通过引用根本数据库结构创建的Northwind.dll,可以对实体类直接进行编译期检查(实际上,编辑时就已经可以动态检查了)。

  要知道,这对我们的数据库开发意味着什么! 重构、消除硬编码、可读性、开发效率提升、数据库平台无关。。。O/R Mapper再优雅,也必须要进行映射,只要稍复杂的系统,要屏蔽开发人员对数据库的了解都是不可能的,而O/R Mapper分离business layer和data access layer的功能对于Comega来说完全没有冲突,DAL层和BL照样可以存在,而生活却一下子变得美好了很多。

  可以说,从一个数据库开发人员的角度来说,Comega的这种特性也正是我所需要的,好像Andres Hejlsberg在讲C#3.0时也提到了类似的特性,不错,我们要的就是这种东西。

 

    对于很多人来说,存储过程的不可替代性并不是在于它的性能(编译优化对性能能提升多少?),而在于它的编译检查,当你一个表改变名称的时候,你很容易知道哪个存储过程中引用了它(当然前提是你不能写动态SQL),Comega的sql支持让我们在不使用SP的情况保存了这种优势。

  当然就目前来说,只是简单的SQL支持远不能取代SP,但Comega的出现让我们看到了光明的所在。O/R Mapper,什么时候我能彻底抛弃呢?在关系的维护和编译期检查数据库对象能力之中,我宁愿不要关系维护,当然Comega并不和RelationShip支持背道而驰,当这种代码:
  Customer c = (Customer)Session.Load(typeof(Customer), "001");

  Customer c = select Customer from DB.Customers where code = "001";

取代时,我看到的是一种简洁和痛快。

  而且就目前的OCL而言,再怎么支持都是在字符串中写表达式或者通过函数来构造表达式,于是在后者,有的方案便通过给Entity class 加入描述属性名称的public const 字段用来构建expression,但这些,都不是我所希望的。再怎么构造查询,都远不如sql的可读性强,因为sql是描述和操纵RDBMS的最好语言。

  我一直是悲观主义者,尽管我目前在写自己的O/R Mapper框架,但是我依然不看好它。而要彻底地改变目前O/R Mapper的可用性的话,是O/R Mapper中的突变,抑或是类似Comega的直接CLR支持取而代之,还是对象化数据库一统天下,将前两者容为一体?

posted @ 2004-12-06 21:32 progame 阅读(2133) | 评论 (14)编辑