对于构造sql出来的查询结果集, 如何对象化访问?
[ 2008-01-19 16:32:37 | 作者: progame ]
如果只是绑定到列表控件, 那么出来的datatable已经足够了, 但有时候一些查询的结果集, 是用来做中间计算的, 这样带来的问题就是必须以columnindex或columnname去访问datarow取得数据, 而且还有DBNull的问题存在, 当然另外还有部分数据库不支持Guid列, 返回结果只是varchar这种情况, 凡此种种, 导致了对结果集的访问非常麻烦.
但是匿名类型(anonymous type)横空出世后, 这个问题但可以得到一定的改观了, 虽然仍然没有DLinQ那么帅的形式, 但好歹可以对象化访问结果集了:
q.Select(a.OrderID, a.OrderDate, b.OrderDate.As("date"), a.OrderNo)
.From(a).As("a")
.InnerJoin(b).As("b")
.On(a.OrderNo == b.OrderNo);
sql = q.Sql;
ds = s.Query(q);
var orderentry = new
{
Orderid = QueryFactor.GuidField,
OrderDate = QueryFactor.DateField,
Date = QueryFactor.DateField,
OrderNo = QueryFactor.StringField
};
var list2 = QueryFactor.ToList(ds.Tables[0], orderentry);
foreach (var e in list2)
{
Console.WriteLine("{0}, {1}, {2}, {3}", e.Orderid, e.OrderDate, e.Date, e.OrderNo);
}
再续ORM性能测试用例
[ 2007-07-29 12:36:44 | 作者: progame ]
既然是ORM的测试, 就得体现这么几点 :
one-one, many-ony, many-many关系
typed query 类型化查询
entity crud 实体的crud
traverse entity list 实体集合的构造和遍历
从便利性上讲, 需要满足这样几点:
master-details: 保存master, 可以自动保存details, 删除master, 可以自动删除details, 但是还有一种master-details是弱关联, 必须区分开来, 所以测试用例中的delete必须要保证orderitem也删除
实体对象属性的透明获取
这里给出我的性能测试的dbschema和unit test
http://www.cnblogs.com/Files/progame/dbschema.rar
...
阅读全文...
one-one, many-ony, many-many关系
typed query 类型化查询
entity crud 实体的crud
traverse entity list 实体集合的构造和遍历
从便利性上讲, 需要满足这样几点:
master-details: 保存master, 可以自动保存details, 删除master, 可以自动删除details, 但是还有一种master-details是弱关联, 必须区分开来, 所以测试用例中的delete必须要保证orderitem也删除
实体对象属性的透明获取
这里给出我的性能测试的dbschema和unit test
http://www.cnblogs.com/Files/progame/dbschema.rar
...
阅读全文...
ADO.NET、NBear和NHibernate和IbatisNet简单读写性能比较
再续NBear性能测试:ADO.NET, NBearV3, NHibernateV1, NBearLite, NBearLite+NBearMapping性能比较
我总觉得这个例子里对数据库的操作不能反应实际运用情况
希望大家能写成这样的测试
load all categories, and traverse it's products
for(...)
{
category cat = new category(id)
load(cat)
double sum = 0
foreaach(product p in cat.products)
{
sum += p.amount
}
// find entity in cat's products by id and by index
cat.products[id].productname = cat.products[5].productname
}
写测试
// created
category cat = new category(id)
cat.xxx = xxx
....
for (....) // add some products
{
cat.products.add(new product(id))
}
save(cat)
// update
cat = new catetory(id)
load(cat)
cat.xxx = xxx
foreach(product p in cat.products)
{
p.xxx = xxx
}
save(cat)
// delete cat and it's products
delete(cat)
说明:
以实际情况做参考, category以100条数据为测试, 每个category下有30条product
不知大家用ORM的情况如何, 就我本人来说, 有这样几点是主要的:
根据class 生成数据库, 在项目初期可频繁更新迭代数据库的schema, 要做的只是修改domain class
类型化的entity和property便于在上述迭代中重构, 不至于隐藏的sql string中出现和schema不符的对象
关系的使用, cat.products["001"] cat.products.add(new product("002")) p.category.name role.users user.roles
类型化的查询 product.category.name == "abc" & product.price > 100f
附上现有测试我的结果:
Read Performance Comparison(ms)
Repeat Times:2 ADO.NET:46 NHibernate:668 TBP:205 NBear:1246
Repeat Times:4 ADO.NET:94 NHibernate:215 TBP:132 NBear:1631
Repeat Times:10 ADO.NET:207 NHibernate:462 TBP:318 NBear:4083
Repeat Times:20 ADO.NET:413 NHibernate:852 TBP:641 NBear:8155
Repeat Times:30 ADO.NET:622 NHibernate:1260 TBP:951 NBear:12245
Write Performance Comparison(ms)
Repeat Times:40 ADO.NET:204 NHibernate:292 TBP:272 NBear:556
Repeat Times:80 ADO.NET:417 NHibernate:608 TBP:504 NBear:1016
Repeat Times:200 ADO.NET:1102 NHibernate:1533 TBP:1565 NBear:2731
Repeat Times:400 ADO.NET:2617 NHibernate:3861 TBP:2796 NBear:5516
Repeat Times:600 ADO.NET:4011 NHibernate:5079 TBP:4148 NBear:9527
实际上在读这个测试很不公平, 我的TBP太占便宜了, 为什么这样说呢
EntityList<Products> products = s.GetList<Products>();
EntityList<Categories> categories = s.GetList<Categories>();
EntityList<Customers> customers = s.GetList<Customers>();
我的EntityList是在需要时才构造entity的, 如果要这样来一下:
foreach (Products p in products)
{
p.productName = p.productName;
}
那么TBP的速度马上就和NBear相当了, 在这不得不PF NH的构造实体集合的速度
而在写测试上, 为什么TBP和Ado.net如此接近,? 实际上是Ado.Net的测试写得有问题
SqlHelper.ExecuteNonQuery(conn, CommandType.Text, "update Products set UnitPrice = 16.8 where ProductID = " + productID.ToString() );
对于多次循环执行的这样一句SQL, 没有使用DBCommand.PrepaidCommand和Parameter导致它的性能极大的降低了
再续NBear性能测试:ADO.NET, NBearV3, NHibernateV1, NBearLite, NBearLite+NBearMapping性能比较
我总觉得这个例子里对数据库的操作不能反应实际运用情况
希望大家能写成这样的测试
load all categories, and traverse it's products
for(...)
{
category cat = new category(id)
load(cat)
double sum = 0
foreaach(product p in cat.products)
{
sum += p.amount
}
// find entity in cat's products by id and by index
cat.products[id].productname = cat.products[5].productname
}
写测试
// created
category cat = new category(id)
cat.xxx = xxx
....
for (....) // add some products
{
cat.products.add(new product(id))
}
save(cat)
// update
cat = new catetory(id)
load(cat)
cat.xxx = xxx
foreach(product p in cat.products)
{
p.xxx = xxx
}
save(cat)
// delete cat and it's products
delete(cat)
说明:
以实际情况做参考, category以100条数据为测试, 每个category下有30条product
不知大家用ORM的情况如何, 就我本人来说, 有这样几点是主要的:
根据class 生成数据库, 在项目初期可频繁更新迭代数据库的schema, 要做的只是修改domain class
类型化的entity和property便于在上述迭代中重构, 不至于隐藏的sql string中出现和schema不符的对象
关系的使用, cat.products["001"] cat.products.add(new product("002")) p.category.name role.users user.roles
类型化的查询 product.category.name == "abc" & product.price > 100f
附上现有测试我的结果:
Read Performance Comparison(ms)
Repeat Times:2 ADO.NET:46 NHibernate:668 TBP:205 NBear:1246
Repeat Times:4 ADO.NET:94 NHibernate:215 TBP:132 NBear:1631
Repeat Times:10 ADO.NET:207 NHibernate:462 TBP:318 NBear:4083
Repeat Times:20 ADO.NET:413 NHibernate:852 TBP:641 NBear:8155
Repeat Times:30 ADO.NET:622 NHibernate:1260 TBP:951 NBear:12245
Write Performance Comparison(ms)
Repeat Times:40 ADO.NET:204 NHibernate:292 TBP:272 NBear:556
Repeat Times:80 ADO.NET:417 NHibernate:608 TBP:504 NBear:1016
Repeat Times:200 ADO.NET:1102 NHibernate:1533 TBP:1565 NBear:2731
Repeat Times:400 ADO.NET:2617 NHibernate:3861 TBP:2796 NBear:5516
Repeat Times:600 ADO.NET:4011 NHibernate:5079 TBP:4148 NBear:9527
实际上在读这个测试很不公平, 我的TBP太占便宜了, 为什么这样说呢
EntityList<Products> products = s.GetList<Products>();
EntityList<Categories> categories = s.GetList<Categories>();
EntityList<Customers> customers = s.GetList<Customers>();
我的EntityList是在需要时才构造entity的, 如果要这样来一下:
foreach (Products p in products)
{
p.productName = p.productName;
}
那么TBP的速度马上就和NBear相当了, 在这不得不PF NH的构造实体集合的速度
而在写测试上, 为什么TBP和Ado.net如此接近,? 实际上是Ado.Net的测试写得有问题
SqlHelper.ExecuteNonQuery(conn, CommandType.Text, "update Products set UnitPrice = 16.8 where ProductID = " + productID.ToString() );
对于多次循环执行的这样一句SQL, 没有使用DBCommand.PrepaidCommand和Parameter导致它的性能极大的降低了
我需要什么样的ORM(对象持久层)
[ 2006-05-04 21:48:27 | 作者: progame ]
首先声明,标题中是“我”,不是“我们”,别人希望如何我不太能够帮着下结论。
一个可以打动我的持久化层(Persistence Layer)或者说OR/M(Object Relateion Mapping)应该具备哪些特征呢?
1、简单,尽可能地简单
没必要为了我偶尔用到的功能花费太多的精力,CRUD满足之后,关于Relation如何处理的问题,我觉得尽可以不必那么讲究,一定要那么OO吗? 一定要 order.items这样去访问order的明细吗? 我觉得太可不必,为了实现这种功能,一是我必须再设计Entity类,以决定有哪些OnetoOne、OnetoMany, ManytoMany的关系,然后会定义一个类似这样的很OO的class出来:
class order
{
.....
customer _customer;
entitylist<orderline> _items;
}
看上去真的很帅,但是我必须去维护它,因为不是所有的关系都需要这样定义,lazy loading并不能让人就可以放肆地定义一个很“胖”的类出来。
如果有人说我可以先class,再使用schema工具生成数据库,那么很不幸,我们没有共同语言了,起码我现在对这种方式不感兴趣,而且我也从来不这样做,像如何让union all构造出来的view利用到索引里所说的一样,我会因为数据库增加一些不相关的列,也会因为性能而再增设冗余,用class的方式去思考的话,我很难知道最终的数据库要做多少修改。如果仍然用“表”的方式去先构建“类”,那么我觉得这是一种掩耳盗铃的行为。顺便说一句,我暂时对domain object还不是很感兴趣。entity就是用来存储数据的,其它的事千万别让它去承担。
那么我希望如何处理relation呢? 非常简单:
entitylist<orderline> items = pl.getList(order, typeof(orderline));
那么如何生成filter呢? 命名规则+代码生成,用order的主键id的值,以及用orderline的order_id列,构造select ... from orderline where order_id = order.id
2、透明,让我知道所发生的一切
我不希望在保存一个或一组entity时,会发生我并不知道的级联更新,或者有些认为我没有dirty flag而不做任何更新,因为有时候一个update t set f = f 并不是什么活都不干的,当我要retrieve时,别因为缓存中已经有了就不从数据库加载了,因为可能我确实需要最新的数据,或者把数据缓存而不提交,这样我的另一个client会因此而无法即时获取数据,数据库的连接也要让我知道,是使用了连接池还是立即释放掉了,什么时候会开启事务,什么时候会提交事务,这些,我统统要知道。
有人会有意见了,ORM不就是为了隔离数据库么,你要知道那么多鸡毛蒜皮的小事干什么?
我只能说,这些东西如果我不知道,那么我就很难写出对数据库优化的处理。而需要这个的话,仅仅是可以trace generated sql是不够的,我希望是当告诉持久层去买烟时,它不要很机灵地顺便买个打火机回来,尽管很多时候这个机灵是很讨好的,但有时候可能会因此给我带好不必要的麻烦。
这里透明的意义就是可控性,当我要它做的时候再去做。
3、可测试性,减少重构或者维护的工作量
这个重要了,假如说我要构造一个查询,怎么办? criteria.add(a.ID like 'a',LogicOperator.ADD)? 这种方法又似乎很OO了,但是当要构造一个
(a and((b or c) and c)这样的条件时,写出来的语法可能连你自己都搞不清楚之间的关系了, 而且如果再加上join,再加上select fileds,会是什么样子?相当于原来SQL的语法树了,假如再来一些,计算列,case 判断,group,having,order by, exists... 天啊,受不了,还是用VIEW吧,可是view还得处理filter的问题,那么,换做Store procedure吧,传递的参数怎么办?用
(@a is null or a = @a)这样么? 再定义那些parameters,这个SP写得就比较难看了,再多来点if else的处理吧,SQL脚本就更长了...
一个查询或者复杂的更新,如何是最易于理解的? 就是SQL,要用对象化来转述它,只能让人看得云里雾里,ORM要不要去处理这些事情?我觉得要。但是就是最后的实现方式一易于理解,二要可验证是否正确,三要易于维护。
用cirteria构造,难于理解,也无法完全验证;用SP,难于维护,当加一个filter时,又要去修改sp对应的CLASS,如果不用sp<->class,那么关于参数的验证又无法保证了,因为可能有个地方你调用了exec sp @a,@b,@c,但后来这个SP可能参数定义,参数位置,参数个数都改变了,原来的调用就隐藏了一个BUG了,如果测试做得足够好的话当然没话说,但你真能做到100%的覆盖用例?要知道还有大量的if else存在。
那么我现在是如何做的呢?很简单,将SQL定义和代码分离,你放哪都行,怎么加密随便你,SQL的写法是这样的:
select a,b,c from t where #x# and #y# or z = :z
#x#是一个filter,当没有fitler定义给它时,它会用1=1替换,:z是参数。
这样有什么好处? 首先这条语句是可检验,当我用xml同样定义了filter后,我可以将对应的filter替换,并用相应的值替换:z,然后我就得到一个完整的SQL语句,这个SQL是可以提交到数据库去检验的。那么如何设置参数的实际值呢? 还是通过命名规则来映射,这个值会来自我程序内部维护的一个data store。
4、性能,瓶颈不能发生在这个地方
虽然说数据库执行SQL的时间会远大于ORM层处理和生成SQL的时间,但我的要求就是生成的SQL千万不要和手写SQL相差太多,对于批量的操作,一定要尽可能地快,有些批量的更新要给我一种特殊的操作,比如说对order的所有items设置一个flag,就没必要让我去遍历list,再一个个设置,再提交了,让我在一行代码写完这个处理,并且生成update orderline set flag = 1 where orderid = @id这样的SQL。
而这点和第2点有点重合了,只有当可控性强了之后,才有可能去避免性能问题。
那么对于集合操作呢? 我永远不需要items[3]这样去访问第3条数据,我永远不会加载一批数据,却只为了修改其中的几个,也就是说order.items对我来说没有意义,我会如何操纵这些集合数据呢?
大概是这样的:
C(create):
list = new list();
list.add(item);
pl.addUpdatetoQueue(order);
...
阅读全文...
一个可以打动我的持久化层(Persistence Layer)或者说OR/M(Object Relateion Mapping)应该具备哪些特征呢?
1、简单,尽可能地简单
没必要为了我偶尔用到的功能花费太多的精力,CRUD满足之后,关于Relation如何处理的问题,我觉得尽可以不必那么讲究,一定要那么OO吗? 一定要 order.items这样去访问order的明细吗? 我觉得太可不必,为了实现这种功能,一是我必须再设计Entity类,以决定有哪些OnetoOne、OnetoMany, ManytoMany的关系,然后会定义一个类似这样的很OO的class出来:
class order
{
.....
customer _customer;
entitylist<orderline> _items;
}
看上去真的很帅,但是我必须去维护它,因为不是所有的关系都需要这样定义,lazy loading并不能让人就可以放肆地定义一个很“胖”的类出来。
如果有人说我可以先class,再使用schema工具生成数据库,那么很不幸,我们没有共同语言了,起码我现在对这种方式不感兴趣,而且我也从来不这样做,像如何让union all构造出来的view利用到索引里所说的一样,我会因为数据库增加一些不相关的列,也会因为性能而再增设冗余,用class的方式去思考的话,我很难知道最终的数据库要做多少修改。如果仍然用“表”的方式去先构建“类”,那么我觉得这是一种掩耳盗铃的行为。顺便说一句,我暂时对domain object还不是很感兴趣。entity就是用来存储数据的,其它的事千万别让它去承担。
那么我希望如何处理relation呢? 非常简单:
entitylist<orderline> items = pl.getList(order, typeof(orderline));
那么如何生成filter呢? 命名规则+代码生成,用order的主键id的值,以及用orderline的order_id列,构造select ... from orderline where order_id = order.id
2、透明,让我知道所发生的一切
我不希望在保存一个或一组entity时,会发生我并不知道的级联更新,或者有些认为我没有dirty flag而不做任何更新,因为有时候一个update t set f = f 并不是什么活都不干的,当我要retrieve时,别因为缓存中已经有了就不从数据库加载了,因为可能我确实需要最新的数据,或者把数据缓存而不提交,这样我的另一个client会因此而无法即时获取数据,数据库的连接也要让我知道,是使用了连接池还是立即释放掉了,什么时候会开启事务,什么时候会提交事务,这些,我统统要知道。
有人会有意见了,ORM不就是为了隔离数据库么,你要知道那么多鸡毛蒜皮的小事干什么?
我只能说,这些东西如果我不知道,那么我就很难写出对数据库优化的处理。而需要这个的话,仅仅是可以trace generated sql是不够的,我希望是当告诉持久层去买烟时,它不要很机灵地顺便买个打火机回来,尽管很多时候这个机灵是很讨好的,但有时候可能会因此给我带好不必要的麻烦。
这里透明的意义就是可控性,当我要它做的时候再去做。
3、可测试性,减少重构或者维护的工作量
这个重要了,假如说我要构造一个查询,怎么办? criteria.add(a.ID like 'a',LogicOperator.ADD)? 这种方法又似乎很OO了,但是当要构造一个
(a and((b or c) and c)这样的条件时,写出来的语法可能连你自己都搞不清楚之间的关系了, 而且如果再加上join,再加上select fileds,会是什么样子?相当于原来SQL的语法树了,假如再来一些,计算列,case 判断,group,having,order by, exists... 天啊,受不了,还是用VIEW吧,可是view还得处理filter的问题,那么,换做Store procedure吧,传递的参数怎么办?用
(@a is null or a = @a)这样么? 再定义那些parameters,这个SP写得就比较难看了,再多来点if else的处理吧,SQL脚本就更长了...
一个查询或者复杂的更新,如何是最易于理解的? 就是SQL,要用对象化来转述它,只能让人看得云里雾里,ORM要不要去处理这些事情?我觉得要。但是就是最后的实现方式一易于理解,二要可验证是否正确,三要易于维护。
用cirteria构造,难于理解,也无法完全验证;用SP,难于维护,当加一个filter时,又要去修改sp对应的CLASS,如果不用sp<->class,那么关于参数的验证又无法保证了,因为可能有个地方你调用了exec sp @a,@b,@c,但后来这个SP可能参数定义,参数位置,参数个数都改变了,原来的调用就隐藏了一个BUG了,如果测试做得足够好的话当然没话说,但你真能做到100%的覆盖用例?要知道还有大量的if else存在。
那么我现在是如何做的呢?很简单,将SQL定义和代码分离,你放哪都行,怎么加密随便你,SQL的写法是这样的:
select a,b,c from t where #x# and #y# or z = :z
#x#是一个filter,当没有fitler定义给它时,它会用1=1替换,:z是参数。
这样有什么好处? 首先这条语句是可检验,当我用xml同样定义了filter后,我可以将对应的filter替换,并用相应的值替换:z,然后我就得到一个完整的SQL语句,这个SQL是可以提交到数据库去检验的。那么如何设置参数的实际值呢? 还是通过命名规则来映射,这个值会来自我程序内部维护的一个data store。
4、性能,瓶颈不能发生在这个地方
虽然说数据库执行SQL的时间会远大于ORM层处理和生成SQL的时间,但我的要求就是生成的SQL千万不要和手写SQL相差太多,对于批量的操作,一定要尽可能地快,有些批量的更新要给我一种特殊的操作,比如说对order的所有items设置一个flag,就没必要让我去遍历list,再一个个设置,再提交了,让我在一行代码写完这个处理,并且生成update orderline set flag = 1 where orderid = @id这样的SQL。
而这点和第2点有点重合了,只有当可控性强了之后,才有可能去避免性能问题。
那么对于集合操作呢? 我永远不需要items[3]这样去访问第3条数据,我永远不会加载一批数据,却只为了修改其中的几个,也就是说order.items对我来说没有意义,我会如何操纵这些集合数据呢?
大概是这样的:
C(create):
list = new list();
list.add(item);
pl.addUpdatetoQueue(order);
...
阅读全文...
1

