RSS 2.0 Feed
2003-12 Entries
摘要:经常看到网上很多朋友在探讨O/R Mapping的若干做法,近日在研习Patterns of Enterprise Application Architecture的时候也学到不少关于ORM的理论和实践(该书中有很大篇幅在讲O/R Mapping中的各个细节),不过我理想中的所谓ORM却是源自这个灵感: class BookDataService: IBookDataService... // 选出给定唯一标识的书目信息BookInfo IBookDataService.Select(Guid bookUID){  return (BookInfo)ElegantORM.Execute(MethodBase.GetCurrentMethod(), bookUID);} // 选出与给定名称相似的书目信息BookInfo[] IBookDataService.Select([Criterion.Like] string name){  return (BookInfo[])ElegantORM.Execute(MethodBase.GetCurrentMethod(), name);} // 插入新书目void IBookDataService.Insert(BookInfo bookInfo){  ElegantORM.Execute(MethodBase.GetCurrentMethod(), bookInfo)} // 修改书目信息void IBookDataService.Update(BookInfo bookInfo){  ElegantORM.Execute(MethodBase.GetCurrentMethod(), bookInfo)} // 删除书目void IBookDataService.Delete(Guid bookUID){  ElegantORM.Execute(MethodBase.GetCurrentMethod(), bookUID)} 后注:IBookDataService是数据访问组件的接口;BookDataService是该接口的一个基于ElegantORM的实现(当然还可以有基于内存的、XML的、ADO.NET的各种实现等等);BookInfo是一个数据传输对象(Data Transfer Object, DTO)类,它被业务层的Book实体类用作实体数据的存储,同时负责在层间整体的传输实体的各个数据项。 如果能够完成,我们现在这个项目的数据访问层组件写起来可就爽喽……还是那句话:只要你想,我就喜欢!呵呵...[阅读全文]

posted @ | Feedback (47) |

摘要:关于我最近在做的ElegantORM(codename for an easy-to-use data access layer helper)的一些话题,请progame、天啦(出什么事儿了到底?;)、kaneboy、ghj1976大侠以及感兴趣的朋友们继续指点、评论。你们的建议对我很有启发和帮助,TIA! http://blog.joycode.com/jgtm2000/posts/10064.aspx...[阅读全文]

posted @ | Feedback (5) |

摘要: ASP.NET使用动态编译技术,在运行时动态将同一目录的*.aspx文件先生成*.cs,然后调用CompilerServices将其编译成assemblies(可以到你的%SYSTEMROOT%\Microsoft.NET\Framework\V1.x.xxxx\Temporary ASP.NET Files下面看看)。因此了解ASP.NET编译的过程是优化ASP.NET运行效率的关键之一。以常用的<%# %>数据绑定语法为例,我们可以发现它的转化规则是: .aspx:  <%# data-binding expression %> -> .cs: System.Convert.ToString(data-binding expression); 其中data-binding expression是原封不动复制过来的,这样你写数据绑定表达式的时候就心里有谱了吧。关于常见于数据绑定表达式中的Container、DataItem、DataBinder.Eval是这样:DataBinder是System.Web里面的一个静态类,它提供了Eval方法用于简化数据绑定表达式的编写,但是它使用的方式是通过Reflection等开销比较大的方法来达到易用性,因此其性能并不是最好的。而Container则根本不是任何一个静态的对象或方法,它是ASP.NET页面编译器在数据绑定事件处理程序内部声明的局部变量,其类型是可以进行数据绑定的控件的数据容器类型(如在Repeater内部的数据绑定容器叫RepeaterItem),在这些容器类中基本都有DataItem属性,因此你可以写Container.DataItem,这个属性返回的是你正在被绑定的数据源中的那个数据项。如果你的数据源是DataTable,则这个数据项的类型实际是DataRowView。 现在你可以想想下面哪种写法效率最高(以Repeater+DataTable数据源为例): <@% DataBinder.Eval(Container.DataItem, "ColumnName") %> <@% DataBinder.Eval(Container.DataItem, "ColumnName", null) %> <@% DataBinder.Eval(Container, "DataItem.ColumnName", null) %> <@% ((DataRowView)Container.DataItem)["ColumnName"] %> <@% ((DataRowView)Container.DataItem).Row["ColumnName"] %> NOTE: 后两种用法需要引入System.Data名称空间……答案一天后揭晓,欢迎有空的朋友自己测试得出结论! 揭晓+简要分析: 乍一看1-3都是使用DataBinder.Eval方法来进行数据绑定计算,而4-5是使用strong type直接获取数据绑定的值。按照我之前的推理,很多朋友会认为4-5都会比1-3快,而实际上第4种用法也是在网上很常见的一种针对DataBinder.Eval而进行的“优化”。 实际上根据我们的测试,第4种写法的效率在某些很常见的情形下(即传入的字段名与数据表内部的字段名大小写有出入时)甚至比不上最普遍的第1种写法。不过原理还是对的,就是避免通过reflection或类似机制(如System.ComponentModel中的PropertyDescriptor机制)获得数据,然而使用DataRowView的indexer的效率在字段数量较多导致Hashtable产生寻址冲突时不如使用其Row属性(DataRow类型)的indexer的效率。原因是DataRowView的indexer实现了view的功能,而这个功能对于大多数应用在这个场合都是不需要的,且它的开销甚至比DataBinder.Eval还要大!(本段内容过于武断,在被反复质疑之下我又做了若干试验寻得正确原因)因此简单的使用第五种写法通常是可以获得较佳的性能的,而最好不要在不必要的时候直接使用DataRowView的indexer。 现在回到1-3的讨论。首先一点,请大家注意看Eval方法的二种overload: object DataBinder.Eval(object container, string expression)string DataBinder.Eval(object container, string expression, string format) 注意到ASP.NET在生成的.cs文件中是使用System.Convert.ToString来将Eval的结果转换成string的,因此显式的提供值为null或String.Empty的format参数将使得Eval首先调用第一种方法得到绑定结果的对象,然后直接调用该对象的ToString()方法将其返回到Convert.ToString方法,对于该方法编译器已经在编译期将其连接到Convert.ToString(string)的重载上,而该方法则直接返回传入的字串。那如果直接使用第一种方法呢?虽然第二种方法是先调用第一种方法的,但是由于它的返回值是object类型,编译器将为其选择Convert.ToString(object)的重载,在这个重载方法中将进行一些额外的判断以将对象转换为string类型,而这些额外判断显然带来了额外的开销——尽管基本上算不得主要矛盾。 至于说第3种写法,由于在expression参数中多引入了一层间接,因此需要多进行一次反射以解析表达式,因此效率非常之低。 那这里再卖个关子,请推测第5种方法是否还可以进一步优化?(我是指在最常见的ASP.NET开发情形中):P 通过上面的分析,我们可以得到下面的结论: DataBinder.Eval是最常用也比较易用的数据绑定表达式写法,但由于其实现机制使用了反射,所以需要关注其所带来的性能损失。通常,当应用开发进入稳定期后可以针对性的对这些表达式进行优化。 但是优化不是光从字面上就能感觉到的,第4种所谓优化随处可见,然而在某些情况下它反而带来其他环节的开销,带来比较低的执行效率。 要注意方法重载是一种编译期机制,通过显式告诉编译器需要使用的方法重载,通常可以在得到同样结果的前提下获得更佳的性能。 性能虽重要,功能价更高——在一般的项目开发中,还是首先关注功能的实现,然后再通过实际测试有针对性的优化比较突出的性能瓶颈。 希望我的这点儿心得对您有所启发。:)...[阅读全文]

posted @ | Feedback (17) |

摘要:关于写这篇随笔所依据的原始测试结果列出如下:(点这里下载测试源代码,17KB,VS.NET 2003,C#) *1:这就是我在原文中所说的“第4种写法的效率甚至比不上最普遍的第1种写法”的出处。其原因已经分析清楚,是和DataRowView的字段数量和Hashtable在按字段名检索字段时的冲突有关,但在少量字段情况下并不常见。不过既然有出现的机会,在最佳实践中还是尽量避免使用为妥。DNW_GetRecentPosts是.Text用到的一个存储过程,它返回35行共18个字段,我就是在用它进行测试时发现DataRowView的索引符性能低下的(引用FeedbackCount字段时)。 *2:在最简单的情况下,虽然DataRowView[]和DataRowView.Row[]的效率都很好,但还是可以见到近一倍的差距。况且在某些情况下,DataRowView[string]的效率会急剧下降,因此我还是在建议最好坚持使用其Row索引符。 3:无论在什么情况下,可以看出使用int字段索引都可以得到非常之快的性能。虽然在实践中很少允许这样编码,但我猜想通过使用强类型的custom data object collection/list作为数据源,用其封装System.Data中常见的数据源(data tables, etc),并在内部使用column index访问字段应该可以获得最佳的数据绑定性能且不牺牲编码准则。 BTW:看了几个朋友测试的代码,我想可能是因为不精确的方法导致无法分辨不同方法之间的差别。所以建议感兴趣的朋友下载我用来测试的代码并实际运行。而且,这段代码可以很方便的用来测试更多的实现机制(看看代码就知道该怎么做了)。谢谢大家的反馈!:)Ranking A: [DNW_GetRecentPosts/FeedbackCount/100000] 0. 60 ms ( 2%) - ((DataRowView)Container.DataItem).Row[ColumnIndex] 1. 70 ms ( 2%) - ((DataRowView)Container.DataItem)[ColumnIndex] 2. 70 ms ( 2%) - ((DataRowView)Container.DataItem).Row[ColumnIndex].ToString() 3. 71 ms ( 2%) - ((DataRowView)Container.DataItem)[ColumnIndex].ToString() 4. 320 ms ( 9%) - DataBinder.Eval(Container.DataItem, "ColumnName", null) 5. 341 ms ( 10%) - ((DataRowView)Container.DataItem).Row[ColumnName].ToString() 6. 370 ms ( 10%) - ((DataRowView)Container.DataItem).Row[ColumnName] 7. 371 ms ( 10%) - DataBinder.Eval(Container.DataItem, "ColumnName") *1 8. 621 ms (......[阅读全文]

posted @ | Feedback (17) |

摘要:在我的前一篇随笔(ASP.NET中的数据绑定:哪个更快?)中提到了一个关于ASP.NET中数据绑定表达式优化的问题,现在已经更新并加入了新的内容,感兴趣的朋友可以继续就这一话题谈谈你的见解,谢谢!...[阅读全文]

posted @ | Feedback (0) |

摘要:早就看到有前辈在项目开发中使用blog作为团队交流沟通与共享信息的工具,而我们今天终于把.Text系统架在了项目组内部(感谢开心就好提供的关键帮助:Handler Patterns.txt),我个人感觉blog确实是团队成员之间进行良好沟通和信息共享的平台。 顺手去了.Text的几个bug: OPML.aspx使用DNW_Stats来取得所有的blogger列表,纯属偷懒。DNW_Stats是用来取得更新排行的存储过程,如果系统里的blogger没有发表随笔的话,DNW_Stats什么也取不到(PostCount>0)。为此添加一个新的存储过程DNW_OPML:create procedure dbo.DNW_OPMLas  select    Title, Host, Application  from    blog_config并修改OPML.aspx.cs让它使用这个存储过程:string sql = "DNW_OPML"; 还是这个文件,它写出来的XML中声明的encoding(utf-16)和Response的encoding(utf-8)不一致,这会导致某些浏览器报错(说不能进行编码转换)。原因是代码中使用了StringWriter作为XmlTextWriter的内部写入器,而StringWriter只能写入Unicode(UTF-16)编码的内容,因此XmlTextWriter会自动将写入的的encoding声明为utf-16。解决的办法是使用XmlTextWriter(Stream, Encoding)构造器构造Xml写入器,直接传入Response.OutputStream和System.Text.Encoding.UTF8,这样生成的Xml结果才会包含正确的encoding声明。虽然不是什么大问题,在大多数情况下也可以正常使用,但这的确是一个很错误的做法。.Text的MainFeed同样存在这样的问题,就不赘述。...[阅读全文]

posted @ | Feedback (2) |

摘要:前面提到了一个关于ASP.NET中拦截并分发动态创建控件事件的问题,有几个朋友给了热心的回复,但是我想可能是我没说得太清楚,或者的这几位朋友还没有遇到这类问题。实际上,如果你主要使用ASP.NET提供的RAD快速开发技术,那可能确实不太会去考虑这样的问题(因为在某些应用环境这确实也算不上是问题,但在我们的项目或者对性能要求比较苛刻的项目中,这绝对是个明显的问题)。这个问题应该算是性能优化范畴,算不上是功能实现的范畴。况且你们提到的办法也不相关于我所叙述的问题——我说的是要解决“运行时动态创建的控件”的事件拦截与触发,静态控件根本不存在这个问题。 我正在把我研究出解决该问题的一种方法写进我的第一篇文章中,欢迎大家提出你们对本问题的想法,或对我提出的方法进行讨论。让我们共同进步,谢谢!...[阅读全文]

posted @ | Feedback (0) |

摘要:昨天在项目开发组里面又遇到了一个老问题,就是在ASP.NET中如何捕获由数据绑定驱动的动态创建对象(比如一个“删除该行数据”的按钮)的事件?常见的办法(比如RadioButtonList等控件)就是通过ViewState等页面存储机制保存已经绑定好的数据和控件,这样既增加了页面的大小,也增大了通信负荷(ViewState里面基本上保存了HTML中表现的数据的副本,DOUBLE!);另一种办法(比如使用Repeater/DataList控件时),就是每次都重新绑定数据,保证页面在Init的时候能够Find到相关的动态对象并触发它的相应事件,这样主要是增加了服务器端处理的负荷,尤其是每次数据绑定都从数据源获取的话。 因为我们对前端开发制定了一些准则,比如说页面功能的执行尽可能通过OnCommand事件处理程序集中(交给页面处理组件)处理,所以昨天晚上搞出来一个在这个准则下解决此问题的办法,稍后整理成文和大家分享。 不过在此我也想请有经验的朋友谈谈解决这个问题的思路,希望能看到解决这个问题更好、更通用的办法(我在Google搜了半天好像还真没找到什么特别好的解决办法)。Thanks! :)...[阅读全文]

posted @ | Feedback (5) |

摘要:看得出很多朋友都对.Text这个东东感兴趣,我个人感觉.Text的实现机制确实有不少很巧妙的地方值得学习,虽然它不像Pet Shop .NET 那样是一个完整的三层结构ASP.NET应用程序,但是其中的很多细节还是可以让你对ASP.NET乃至.NET Framework的机制有更深刻的了解。 我们最近的项目还是很忙,我希望能够利用一些业余时间整理一下关于.Text架构设计与实现方面的内容以文章的方式发布出来。其间如果你有什么好的建议或关于.Text的问题可以通过我的联系页面发给我,非常高兴能与大家分享关于.NET的心得,谢谢!...[阅读全文]

posted @ | Feedback (2) |

摘要:初来乍到,写了两天随笔,却总觉得还有点儿没灵感。熟悉我的朋友可能知道,在网上我“接下茬儿”比较踊跃,真正原创并不多,一方面是精力有限,另一方面文笔也实在不登大雅之博客堂。 前两天开心就好给我提了点儿建议,说可以借这块宝地虚拟一个团队,和感兴趣的朋友们共同开发一个比较通用点儿的项目,然后在这个过程中以“讲故事”的方式把随笔的数量级搞上来……(是这个意思吧开心?)我顺着他这个思路想了想,感觉首先得确定个选题范围,就是说开发个跟哪方面有关系的什么东西?(看出我文笔烂了吧!) 我想,既然是为了写东西与大家分享经验、技巧和乐趣,那么开发这个东西就应该能够体现我们的经验和技巧,而且还得比较有乐趣。作为我来讲,一时还真说不清楚自己到底哪方面特别擅长,也就是仗着年头久点儿,对什么都有点儿兴趣罢了。所以这里很想从博客堂的朋友们这里得到些提示,看看有什么能够引起共鸣的事情可以一起做做,或者哪怕就以“讲故事”的方式虚拟的做做。 下面是一些我自己比较感兴趣的话题,大家给点儿反馈如何? 最近有不少朋友在研究.Text,由于.Text还是个处在beta期的开源.NET项目,它也很自然成了很多朋友研究和学习.NET网络应用程序开发的又一个蓝本(此前.NET Pet Shop 3.0已经成了不少朋友实战.NET的众矢之的了)。虽然我暂时还没有兴趣做这方面的东西,不过如果有朋友有兴趣研究这个,我很愿意结合其设计模式与实现机制等具体问题与大家讨论,一起学习。 要说讨论和学习,Microsoft这两年来一直在做的Patterns and Practices算得上是最有嚼头了。其中的文档、应用构建模块、参考架构等等既实用又通俗易懂,真乃不可多得的宝物。然而在研究这些东东的过程中难免会遇到各种问题或冒出不少想法,这时候有个人能一起讨论甚至争论争论又该是何其幸福啊,是吧? 真正能拿来做的,我倒是有一个小项目。想得很早,大概是在刚拿到VS.NET 2002之后不久就萌发的念头,是关于.NET中的configuration可视化管理的。这个项目如果要做,大概涉及这么几个环节:XML,Remoting/Web Services,Win Form/Web Form双界面,国际化,VS.NET集成等等。域名都注了,就是一直没找到伙伴做,也许和博客堂里的朋友们就随了愿呢…… 不过这个要做得快,还得做得好,不然等VS.NET 2004出了就没彩儿了(也不一定的说——只要你想,我就喜欢!)。 还有一个,暂时还不能拿出来做,不过如果有朋友对这些技术的开发有经验或感兴趣的话希望你能和我多交流:SQLNS、.NET Alerts。 得了,先抛这么几块砖头吧,明儿早上回来接玉的说。该回家吃饭喽……...[阅读全文]

posted @ | Feedback (3) |