??xml version="1.0" encoding="utf-8" standalone="yes"?> 理上的问题不能得到d的解冻I软g的质量保障就无从谈v。笔者最q在与印度一安过了CMM4U评估的软g公司Q以下简UA公司Q进行合作的q程中,较ؓ(f)详细C解了他们有关目理的一些详l情况,更深d感受C目理的规范化与企业Y件质量保障之间的密切关系。下面想着重从软g企业的构Ӟ软g目计划、项目管理、项目经理的职责{方面对印度软g的项目管理及(qing)我国软g质量保障应注意的问题q行一些经验ȝQ供业内人士参考?BR> (1)A公司l构 ?是A公司的组l结构图Q同国内公司差异较大的部门有QA、SSG和h力资源部门?
* A公司中,QA(Quality Assure)部门与研发部门独立,负责监督程的执行。QA同时负责领导与研发部门组成的联合工作l,制定公司程? (2)目l结? 1) A公司寚w目组q行独立核算Q项目具体负责h为PC(Project Coordinator)Q负责项目计划和执行Q对目具体成员q行分工。在每个阶段的结束会(x)议上(如概要设计结?QPC要接受QC(Quality Coordinator)的审查。除了PC与QC的接口外Q所有其他外部接口都由EM(Engineer Manager)完成QEM负责与客h交道Q向SSG、h力资源要求资源,与其他项目组协调q度?BR> 3) 印度工程师分?U,半年一ơ考评Q即半年有一ơ升U机?x)? A公司规定Q一人最多可以同时兼M个项目的PCQEM理的项目没有限制? A公司通常的项目组??人,最多不过10人? 以上是A公司Q同时也是印度大多数规范化的软g公司Q的l织l构和项目组l构。可以看出,A公司的组l结构非常清晎ͼ各个部门分类非常l,d明确QY件生产的每一个步骤都有专门的部门、专门的人员负责Q从最基础的开发h员到负责l领全局的ȝ理,层层理Q沟通渠道畅通。而在我国Q管理的不规范往往首先体现在公司的l织l构上,集中表现为部门的~失和管理的交叉上。我国的软g公司Q大部分规模较小Q开发h员超q?00人的公司很少。在印度QY件公司无论大,都是“麻雀虽小Q五脏俱全”,l不?x)因为公司的规模大小而改变合理的l织l构。因此笔者认为,国内的Y件企业要x效地保障产品质量Q首先就要在构架合理的组l结构上下功夫,q就如同盖高楼首先要打好地基一P地基不打牢,l构不合理,其他斚w再下功夫也是徒劳。有Q因为国内Y件企业规模小Q所以造成l构讄的欠~,但笔者认为恰恰是因ؓ(f)没有建立一个规范化的组l结构,才会(x)使Y件品质量不保,q而严重媄响了企业的发展扩大? 2.目计划 凡事预则立,不预则废。这里的“预”就是指计划。对于Y件企业,计划的重要性是不言而喻的。让我们先看看A公司的项目计划是如何制定?在A公司Q项目开始之前必d估计目的规模(以代码行数来衡量Q?然后制定目计划。通常旉??周,已知的最长有5周。EM负责制定目 EWP(Engineer Work Paper)Q其中定义了目需要的人力和计机资源Q由相关部门同意Qƈ报研发总负责h批准后才能开始项目? 目的正式开始时间由目l的Kickoff MeetingvQCloseout Meetingl束? 大概很多人都听过q样一句话Q“计划赶不上变化”。这U“变化”对某些行业而言也许q不?x)生太大的影响Q但对于软g企业而言Q却?x)给软g产品的质量保证带来严重的负面影响。ؓ(f)什么会(x)造成q种“计划赶不上变化”的现象Q究其原因,W者认Z要是因ؓ(f)对计划的重视E度不够Q计划过于笼l、粗p导致可执行性太差,再加上一些h为因素的影响Q必然会(x)产生q样的后果? 如果我们的Y件企业都能像A公司q样Q在作计划时能考虑到每一个细节,不是仓促做出军_Q而是由所有的相关部门共同对品计划进行反复研I、制定、讨论、修改,最lŞ成一套系l、严密、具有很强的可执行性的计划。计划一旦Ş成,׃格按照计划去执行Q而不受某个h、某件事的媄响,那么׃仅能够减大量资源的费Q品的质量也得C保障? 因此Q对计划的高度重视、周密制定、严格执行是企业有效保障产品质量的一个重要环节? 3.目理 当企业构架了合理的组l结构ƈ制定了缜密的计划后,p入了产品的开发阶Dc在q个阶段中,目理起了重要作用Q它所涉及(qing)的环节相当具体复杂,下面先介l一下A公司在项目管理上的具体细节:(x) (1)开发阶D和目周期 * A公司Ҏ(gu)E比寚w目更重视? (3)计划 1) 计划详细、周到? 2) 程中明定义开发阶Dc?BR> 4)每个阶段l束都要召开阶段l束?x)议。前一个阶D늻束才能进入下一阶段? 5)计划中每个活动都比较具体Q每个活动的旉以天Q半天)为单位。计划包括了开展质量控制活动的旉? (4)Review 按印度公司流E,一般把Review和测试作Z证Y件质量两个主要手Dc测试的重要性就不需说明了,而Review则是一个非常简单有效ƈ能尽早发现Y件中错误的方法,可以_(d)M交付物都要经Review后才能进行基U化。目前A公司有很详细全面、可执行性很高的Review程和各U交付物的Review Checklist? 在印度Y件企业,现有q么一句口P(x)凡事有计划,凡事必review? (5)QA QCQ质量经理)作ؓ(f)质量保证部门QSQAQ的代表Q监督和保证目的进展遵循QMS各项程和模板,q且攉目中发现的一些问题和解决Ҏ(gu)以优化流E? (6)度量数据 CMM中比较强调用数据说话Q对目q程中基本上所有的数据都会(x)有记录,最后把攉的数据提交质量保证部门进行分析,以改q流E。A公司的项目经理和质量l理很重视项目中的数据收集,包括各种Review数据、测试数据以?qing)项目组员每天的zd数据{。项目经理也要维护一个项目档案,在这个项目档案中可以说包含了目开发过E中所有的产出、开发活动、管理活动等的记录。可以这么说Q有了这个项目案,你就可以完全了解q个目的开发过E? (7)团队_ 印度公司都比较强调团队精、合作精,应该_(d)其流E本质上p求员工之间的互相协调和理解。相对而言Q印度员工的合作_和协调精都比我国员工要好得多?/FONT> (8)培训 印度公司都比较强调培训,一般有专门的培训部门进行协调。在新员工进入公司后都会(x)有公司流E和其他一些公司普遍章E的培训Q以保证员工Ҏ(gu)E的理解和执行。对于具体项目,目l理在制定项目计划时׃(x)在项目计划中提出所有的培训需求,包括技术上的培训和其他所需的培训? (9)配置理 记录?qing)时、充分、比较准。这些记录包?重要的邮件、会(x)议纪要、审核记录、缺h告、测试报告?BR> 2)Ҏ(gu)有的zd都有一个跟t落实的q程Q比如对所有的Review记录和更改请求都?x)有一个状态标识,标识其当前状态,通过跟踪其状态来监督其落实? 3)Ҏ(gu)有的zdQ包括对文档和代码的更改都会(x)有一个历史记录? 4)记录比较准确、比较客观? 5)许多记录都是通过定量的数D录,以数据说话(CMM4U的重点是量化理Q? 以上是A公司在项目管理中所涉及(qing)到的一些主要环节,很值得国内的Y件企业在制定目理规划时借鉴。除此之外,我国的Y件企业在产品开发管理的q程中,q易出现以下几个斚w的问? 1)需求说明差─需求不清楚、不完整、太概括、或者不可测试,都会(x)造成问题? 2)不切实际的时间表─如果在很短的旉里要求做许多事,出现错误是不可避免的? 3)试不充分─只能Ҏ(gu)客户意见或系l崩溃来判断pȝ的质量? 4)不断增加功能─在开发正在进行过E中要求增加许多新的功能。这是常见的问题? 5)交流问题─如果开发h员对客户的要求不了解Q或者客L(fng)不恰当的期望Q必然会(x)D错误?BR> 1)可靠的需求─应当有一个经各方一致同意的、清楚的、完整的、详l的、整体的、可实现的、可试的需求。ؓ(f)帮助定需求,可用模?(prototypes)? 2Q合理的旉表――ؓ(f)计划、设计、测试、改错、再试、变更、以?qing)编制文档留够的旉。不应用突ȝ办法来完成项目? 3)适当试─早开始测试;每次攚w或变更后Q都应重新测试。项目计划中要ؓ(f)试和改错留够时间? 4)可能坚持最初的需求─一旦开发工作开始,要准备防止修攚w求和新增功能Q要说明q样做的后果。如果必进行变_(d)必须在时间表上有相应的反映。如果可能,在设计阶D用快速的模型Q以便客户了解会(x)得到的东ѝ这会(x)使他们对他们的需求有较高的信心,减少以后的变更? 5)沟通――在适当时机q行预排和检?充分利用团组通信工具―电(sh)子邮件、群?groupware)、网l故障跟t工兗变更管理工兗以?qing)因特网的功能。要保文g是可用的和最新的。优选电(sh)子版文档Q避免纸介质文:q行q距联合作业及(qing)协作;早使用模型Q客户的预惌达清楚? 4.PCQ项目经理) 目l理是项目成败的关键人物Q其寚w目的成|负主要责仅R因此在q里项目经理的有关内容单独提出Q以A公司Z详细说明PC在整个品研发过E中所扮演的角Ԍ希望能对国内软g企业的项目经理有所启示? Q?)在A公司Q按程在一个项目正式开展之前,目l理需要完成:(x) * 目计划(Project Plan):在此描述整个目所应完成的交付物、项目时间表、培训需求、资源需求、质量保证计划以?qing)过E和交付物的定量质量目标{? * 目配置理计划(Project Configuration Plan):在此指定配置理员,描述目配置列表、配|管理库、版本管理计划等{? *目q程手册(Process Handbook):在此描述本项目所采取的裁剪后的生命周期模型和程? Q?Q在目开发过E中Q项目经理需非常了解目q度Q进行工作Q务细化、具体计划和安排目成员工作d{工作。对H发事g目l理需能及(qing)时合理地q行协调? Q?)ȝ说来QPC安排工作有这么几个特? a.PC对Y件开发具有丰富的l验Q了解Y件开发的普遍程Q了解各个阶D|需完成的工作,q是安排好项目组成员工作的前提,在A公司对PC的整体素质要求非帔R? b.在项目正式开展前QPC准备目计划文Q在目计划中包含了目q度旉表,但此旉表比较粗Q只能给出各个阶D和各个子阶D늚起始l束日期。对各个阶段和各个子阶段的详l工作安排和各项工作责Q人只能在目开展工E中Ҏ(gu)目实际情况q行安排Q一般是在每周项目组例会(x)上进行本周详l工作安排?BR> * PCҎ(gu)目q展非常了解。了解渠道通常是每周组员的状态报告和直接与组员接触了解,q也需目l成员能如实汇报工作? * 对现阶段或本周所需完成的工作非怺解。知道现在该做什么,q且能把各项工作q行合理l致地划分,因ؓ(f)各个分解的工作比较细_(d)因此能相对精地评估些工作完成所需的时间? * PC寚w目组员的能力比较了解Q安排工作时能做到有的放矢。当安排的员工对工作不熟(zhn)时Q会(x)指定相应的组员进行协助? * PC对组员的工作安排都比较细致饱满。一般不?x)出现有些员工有事干Q有些员工没事干的情况,当出现这U情冉|员工提前完成工作ӞPC׃(x)q行相应的协调? d.PC在项目组例会(x)上的工作安排一般只限于本周或甚xq后的二、三天,一般不?x)太长,寚w旉工作的安排容易失ȝƈ且不易控制。相对而言Q短旉的工作安排就比较_而且Ҏ(gu)控制Qƈ且能不断Ҏ(gu)完成的工作进行调整。当Ӟq就要求PC能根据项目计划中的项目时间表q行整体q度的把握?/FONT> e.目l例?x)一般一周一ơ(旉不能太长Q,但必要时Q如l员工作已完成或其他事情Q,也可在中途召开目?x)议q行工作安排Q一般时间都比较短(十几分钟左右Q一般不过半小Ӟ以免费旉Q,MQ当PC觉得需要时Q就?x)召开目?x)议? f.当项目组出现意外事g或媄响项目团l的事gӞPC能及(qing)时合理协调,解决目l内的不和谐气氛?BR> 以上l合印度软g目理的经验ȝ了一些我国Y件质量保障应注意的问题。曾有h提出:q样一呛_学习(fn)模仿Q民族Y件工业没有多大希望。但W者认为,在这个问题上不妨采取“拿来主义”的办法Q对于好的,事实证明是成功的l验Q首先是“占有”,然后才是“挑选”和“创新”。如果能把印度的理l验真正领会(x)q付诸实践,怿Ҏ(gu)们的民族软g工业一定会(x)起到U极的推动作用?/FONT> ADO.NET是专门ؓ(f)帮助开发h员开发高效的多层数据库应用程序设计的。ADO.NET对象模型可分Zc:(x)一cMؓ(f)“连接的”,一cMؓ(f)“断开q接的”对象,后者允许将查询l果保存在内存中q行处理?/P>
”连接的“对象模型顾名思义Q它是直接与数据库进行连接操?“断开q接”的对象模型可以说是建立在“连接的”对象模型的基础上进行的Q因为它必须先进行一ơ“连接的”操作,才能得到所需的结果?/P>
举个?Q?nbsp; SqlConnection con=new SqlConnection("server=localhost;database=db,uid=sa,pwd=;"); SqlDataAdapter ad=new SqlDataAdapter("select * from table",con); DataSet ds=new Dataset(); ad.Fill(ds,"table"); //注意q里已经从数据库里查询出来的结果放C个Dataset对象里,从此d始,你就开始用“断开q接”的对象模型来对数据库进行操作,DataSet对象是一个在内存中的”虚数据表“,你可以对它进行Q何操作而不影响数据库,可以对它q行排序Q修改,查询Q增加,删除。而如果你xҎ(gu)据库内容的话Q也可以通过DataSet对象来操作,很简单,调用它的update()Ҏ(gu)卛_完成更新数据库。也可以使用它的GetChanges()Ҏ(gu)来获取只更改q的行,它返回一个DataSetQ这个Dataset不同于调用GetChanges()Ҏ(gu)的那个,q回的这个只是它的一张子表,也就是更改过的数据,利用此方法可以大大地提高多层ADO.NET应用E序的性能。DataSetc还有一个MergeҎ(gu)用来合ƈ两个DataSet对象的数据,ADO.NET默认覆盖被调用Merge()Ҏ(gu)的DataSet中的行?/P>
ADO.NETq提供了一U强cd的DATASET对象Q它可以帮助你简化徏立数据访问应用程序的q程。例如:(x)有个表叫table,其中有一列叫column你可以这h讉K此列Q?/P>
vb.net: Dim ds as DataSet Console.WriteLine(ds.table(0).column); (table(0).表示table表中的第1行) c#: DataSet ds; Console.WriteLine(ds.table[0].column); (table[0].表示table表中的第1行) 是不是很z? ^_^ 关于DataSet里面q有好多东西方便用如QDataTable,DataView,DataRow,DataColumn,DataRelation,Constraint一大堆的好东西Q在以后的日志中?x)提刎ͼ?BR>
计算机和通信技术的q速发展,特别是Internet技术的发展与普?qing),Z业内部、企业与外部提供了快速、准、可靠的信息交流渠道。信息化企业q作理pȝ已成Z事业单位参与全球市场竞争的必备支持系l。正是由于这L(fng)市场需求与技术发展现Ӟ为我国的IT行业带来了空前发展的机遇Q特别是软g行业。Y件企业能否抓住这样一个难得的发展Z(x)需要多斚w的努力,其中软g质量保障在其发展q程中占有重要的位置?众所周知Q印度已成ؓ(f)世界上Y件业增长最快的国家Q目前每qY件业产D数十亿美元,q且q在以每q?0%?0%的速度增长。比较我国和印度的Y件业,׃隑֏?中国拥有巨大的Y件市场和世界公认的Y件开发资源,在基研究和对技术前L的把握上,也有自己的优势,整体社?x)经环境而言也优于印度。此外,中国的Y件开发h员费用比较低廉,仅是世界市场?/3左右。虽然中国hq不~Z软g开发的天赋Q但是在来强调规模化l营的今天,先天不的管理痼疾我们举步l艰Q难以摆脱小作坊式的软g开发模式。而印度Y件业从一开始就立于ؓ(f)国软g企业服务Qƈ遵@其Y件开发的理模式Q与国际标准接轨?
1.软g企业的组l结?
?
* SSG(System Support Group)cM我们的IT部门Q负责公司所有计机软g和硬件资源的分配和管理。所有的办公环境和开?实验室环境由SSG负责安装和维护,计算源属于SSGQ由各个目向SSG提出需求,目l束后,讑֤需要交q给SSG。个人和目l没有固定的软g和硬件资源。SSG是与研发q的部门?
* 人力资源部门负责公司的h力资源管理,q维护员工的技能数据库。项目开始时Q项目组向h力资源申请h力,向SSG甌计算机硬件和软g。项目结束时需要释放计机资源lSSGQ释放h力资源到人力资源池,q同时更新员工的技能数据库。研发部门的人力资源q发总负责h和其助手分配(cM我国各公司的人力资源??
2) 汇报关系?
Team Member->Team Leader->PC->EM->研发总负责h?
1U?Software EngineerQ刚毕业的本U生和研I生?
2U?Senior Software Engineer?
3U?Project Leader?
4U?Project Manager?
5U?Senior Project Manager?
3U可以成为PCQ?U可以成为EM。刚开始^?q升一U,往后升职越慢?
开发阶D|较明显,注重各阶D应完成的功能,Ҏ(gu)阶段应完成的工作不能留到下一阶段?BR>
(2)程
* 软g开发流E非常规范和pȝ化,其流E的可执行性很高,q且能在实践q程中不断改q。A公司的流E已覆盖C一个项目研发的所有方面,包括从最开始的意向到最后Y件的版本发布(release)Q都有相应的程规定Q基本上已Ş成一U工业化的Y件开发?
* 人和程是保证项目成功的两个最关键因素。由好的人按好的程q行目开发,才能最大限度地保证目的成功。一个好的流E可以保证差的h做出来的东西不至于太差,但不能确保做出精品。通过程可以实现一U规范化、流水线化、工业化的Y件开发?
3) 每个阶段都列Z该阶D늚各项zdQƈ详细描述每项zd的属?
* q入条gQ输?
* 验证Ҏ(gu);
* l束条gQ输出?
在项目正式开展前Q项目经理就要制定配|管理计划,q且指定配置理员徏立v配置理库,按配|流E严D行配|管理。在配置程中也详细提供了对更改的控Ӟ没有l过批准的更改请求是l对不能q行的?
(10)记录
1)与客户和其他目l的所有往来必邮件记录?
q些问题的出玎ͼ会(x)对Y件质量的保证产生不良影响Q针对上q问题ƈl合A公司在项目管理方面的l验Q笔者提Z些相应的解决Ҏ(gu)Q以供参考:(x)
c.PC对工作安排往往_到天Q有时甚至精到时Q要做到q一点,需?
g.PC善于鼓励手下Q发挥员工的潜能QPC往往?x)赞扬很好地完成了工作的l员?BR>
从上面可以看出,对PC的能力(包括技术和理能力Q要求是非常高的Q我国的软g企业往往只重视PC的技术能力,但事实上Q一个只_N技术的人往往不能成ؓ(f)一个合格的领导者, W者认为对PC而言Q首先要求他能够比他的下属看得更q一步,利时不盲目乐观Q遇到挫折时不茫然失措,使整个团队始l保持高昂的士气?BR>
ȝ
]]>
http://www.cnblogs.com/William_Fire/articles/125819.html
http://www.cnblogs.com/william_fire/articles/126665.html
http://www.cnblogs.com/tintown/archive/2005/03/23/124395.html
http://www.cnblogs.com/tintown/category/12787.html
http://www.cnblogs.com/tintown/archive/2005/04/04/131784.html
http://www.cnblogs.com/tintown/archive/2005/04/04/131784.html?Pending=true#PostPost
http://www.cnblogs.com/tintown/archive/2005/04/07/132876.html
http://blog.sunmast.com/sunmast/articles/816.aspx
ADO.NET对象模型Q?BR>http://www.phome.net/document/net/200504/net111246243813950.html
http://www.phome.net/document/net/200504/net111246243713949.html
http://www.phome.net/document/net/200504/net111246244913952.html
ADO.NET对象模型
http://blog.csdn.net/jabby12/archive/2004/08/02/59221.aspx
可见Q在分层的时候,我们?x)增加一个实体层Q它的作用如下:(x)
?显C数据和实际的存储区域隔,保证了业务的独立性,提高了可重用性?
?在业务层和表现层之间传递数据。(如果没有实体层的话,我们需要把表的每个字段作ؓ(f)一个参数在它们之间传递,如果修改的话Q将需要媄响到E序的各个层Q?
?提供更大的可收羃性?
2Q?业务实体层的几种选择Ҏ(gu)?qing)其优缺炏V?
?NET环境下实C务实体有下面的几U选择Q?
?DataReader BE h最快的d速度Q用于只ȝ场合Q不hOO的概c?
?XML BE 可以与XML Reader和DataSet转换。缺点:(x)性能低,验证、解析、显C、排序等都很复杂?
?Generic DataSet BE 优点Q数据绑定等。缺点:(x)客户端必通过集合来获取数据,没有cdQ实例化开销大,调度性能低?
?Typed DataSet BE 优点Q由cdQ可以进行类型检查。缺点:(x)只能从DataSetl承Q部|不方便Q可扩展性差Q实例化开销大,调度性能低?
?Custom BE 优点Q性能调优Q代码更h可读性,用自定义实体cd义一个良好的接口Q将复杂问题隐藏在其中。缺点:(x)设计开发都很复杂,需要自己去实现CURD操作Q自己去实现数据l定Q工作量很大?
?O/R Mapping的实?它具有自定义cȝ所有优点,同时实现了CRUDQ数据绑定等操作?
关于ObjectSpaces ?U>llblgen
http://www.llblgen.com/defaultgeneric.aspx
http://www.sinzy.net/blog/Read.asp?ID=44&BID=931
http://www.csdn.net/develop/author/NetAuthor/sun2bin/
]]>http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconworkingwithtypeddataset.asp
Implementing Data Transfer Object in .NET with a Typed DataSet
Version 1.0.0
GotDotNet community for collaboration on this pattern
Complete List of patterns & practices
Context
You are implementing a distributed application with the .NET Framework. The client application displays a form that requires making multiple calls to an ASP.NET Web service to satisfy a single user request. Based on performance measurements you have found that making multiple calls degrades application performance. To increase performance, you would like to retrieve all the data that the user request requires in a single call to the Web service.
Background
Note: The following is the same sample application that is described in Implementing Data Transfer Object in .NET with a DataSet.
The following is a simplified Web application that communicates with an ASP.NET Web service to deliver recording and track information to the user. The Web service in turn calls a database to provide the data that the client requests. The following sequence diagram depicts the interaction among the application, the Web service, and the database for a typical page.
Figure 1 illustrates the sequence of calls needed to fulfill the entire user request. The first call retrieves the recording information, and the second call retrieves the track information for the specified recording. In addition, the Web service must make separate calls to the database to retrieve the required information.
Database Schema
The schema that is used in the example shown in Figure 2 depicts a recording record that has a one-to-many relationship with a track record.
Implementing a DTO
One way to improve the performance of this user request is to package all the required data into a data transfer object (DTO) that can be sent with a single call to the Web service. This reduces the overhead associated with two separate calls and allows you to use a single connection with the database to retrieve both the recording and the track information. For a detailed description of how this improves performance, see the Data Transfer Object pattern.
Implementation Strategy
A typed DataSet is a generated subclass of System.Data.DataSet. You provide an XML schema file which is then used to generate a strongly-typed wrapper around the DataSet. The following two code samples illustrate the differences. The first sample is implemented with an ordinary DataSet:
DataTable dataTable = dataSet.Tables["recording"]; DataRow row = dataTable.Rows[0]; string artist = (string)row["artist"];
This sample indicates that you need to know the table and column names to access the tables and fields contained in the DataSet. You also have to know the return type of the Artist field to ensure that the correct cast is done. If you do not use the correct type, you will get a runtime error. The following is the same example implemented with a typed DataSet:
Recording recording = typedDataSet.Recordings[0]; string artist = recording.Artist;
This example demonstrates the benefits that the typed interface provides. You no longer have to refer to table or column by name and you do not have to know that the return type of the Artist column is a string. A typed DataSet defines a much more explicit interface that is verifiable at compile time instead of at runtime. In addition to the strongly-typed interface a typed DataSet also can be used in all places a DataSet can be used; therefore, it also can be used as a DTO. It is loaded in a similar fashion as a DataSet and it can be serialized to and from XML. In comparison to an ordinary DataSet you do have to write and maintain an XML schema that describes the typed interface. The Microsoft Visual Studio .NET development system provides a number of tools that simplify the creation and maintenance of the schema.The rest of this implementation strategy outlines the steps required in creating a typed DataSet for the sample application just described.
Creating a Typed DataSet
A typed DataSet is generated from an XML schema. Visual Studio .NET provides a drag-and-drop tool which automates the creation of the schema (see Figure 3) and the generation of the typed DataSet classes. If you do not use Visual Studio.NET, you can write the XML schema and use a command-line tool called XSD.exe to generate the typed DataSet. For detailed instructions on both of these methods, see "Typed DataSets in ADO.NET" from the May 2001 issue of .NET Developer [Wildermuth02].
RecordingDto.xsd
The following is the XML schema for the DTO to be used in this example. It combines both the recording table along with its associated track records in a single typed DataSet named RecordingDto:
<?xml version="1.0" encoding="utf-8" ?> <xs:schema id="RecordingDto" targetNamespace="http://msdn.microsoft.com/practices/RecordingDto.xsd" elementFormDefault="qualified" attributeFormDefault="qualified" xmlns="http://tempuri.org/RecordingDTO.xsd" xmlns:mstns="http://msdn.microsoft.com/practices/RecordingDto.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:codegen="urn:schemas-microsoft-com:xml-msprop"> <xs:element name="RecordingDto" msdata:IsDataSet="true"> <xs:complexType> <xs:choice maxOccurs="unbounded"> <xs:element name="recording" codegen:typedName="Recording" codegen:typedPlural="Recordings" codegen:typedChildren="Track"> <xs:complexType> <xs:sequence> <xs:element name="id" type="xs:long" codegen:typedName="Id" /> <xs:element name="title" type="xs:string" codegen:typedName="Title" /> <xs:element name="artist" type="xs:string" codegen:typedName="Artist" /> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="track" codegen:typedName="Track" codegen:typedPlural="Tracks" codegen:typedParent="Recording"> <xs:complexType> <xs:sequence> <xs:element name="id" type="xs:long" codegen:typedName="Id" /> <xs:element name="title" type="xs:string" codegen:typedName="Title" /> <xs:element name="duration" type="xs:string" codegen:typedName="Duration" /> <xs:element name="recordingId" type="xs:long" codegen:typedName="RecordingId" /> </xs:sequence> </xs:complexType> </xs:element> </xs:choice> </xs:complexType> <xs:unique name="RecordingDTOKey1" msdata:PrimaryKey="true"> <xs:selector xpath=".//mstns:recording" /> <xs:field xpath="mstns:id" /> </xs:unique> <xs:unique name="RecordingDTOKey2" msdata:PrimaryKey="true"> <xs:selector xpath=".//mstns:track" /> <xs:field xpath="mstns:id" /> </xs:unique> <xs:keyref name="recordingtrack" refer="mstns:RecordingDTOKey1"> <xs:selector xpath=".//mstns:track" /> <xs:field xpath="mstns:recordingId" /> </xs:keyref> </xs:element> </xs:schema>
This schema is not the exact file produced by Visual Studio .NET. It is annotated with a number of attributes that are prefixed from the codegen namespace. This modification is desirable because the code that is generated does not adhere to the .NET naming conventions. For example, without the modification, Visual Studio .NET would generate a track class that corresponds to the track table, whereas according to conventions used in the .NET Framework the class should be named Track. To change the name of the class that is generated, you must add the codegen:typedName attribute to the element definition in the XML schema:
<xs:element name="track" codegen:typedName="Track"> </element>
There are a number of other attributes besides codegen:typedName. For a detailed description of all the attributes, see "Typed DataSets in ADO.NET" from the May 2001 issue of .NET Developer [Wildermuth02].
Filling a Typed DataSet from the Database
The following code example demonstrates how to fill a typed DataSet with the data that the sample application requires. This includes the specific recording record and all of its associated track records. The difference between this code and filling an ordinary DataSet is that you do not need to explicitly define the relationship between the recording and track records.
Assembler.cs
Just as in Implementing a Data Transfer Object in .NET with a DataSet, an Assembler class maps the actual database calls into the typed DataSet:
using System; using System.Data; using System.Data.SqlClient; using Recording; public class Assembler { public static RecordingDto CreateRecordingDto(long id) { string selectCmd = String.Format( "select * from recording where id = {0}", id); SqlConnection myConnection = new SqlConnection( "server=(local);database=recordings;Trusted_Connection=yes;"); SqlDataAdapter myCommand = new SqlDataAdapter(selectCmd, myConnection); RecordingDto dto = new RecordingDto(); myCommand.Fill(dto, "recording"); String trackSelect = String.Format( "select * from Track where recordingId = {0} order by Id", id); SqlDataAdapter trackCommand = new SqlDataAdapter(trackSelect, myConnection); trackCommand.Fill(dto, "track"); return dto; } }
Note: The example shown here is not meant to describe the only way to fill the typed DataSet. There are many ways to retrieve this data from the database. For example, you could use a stored procedure.
Using a Typed DataSet in an ASP.NET Page
As mentioned previously, a typed DataSet inherits from System.Data.DataSet. This means that it can be substituted for a DataSet. For example, when using the .NET user interface controls (Web Forms or Windows Forms) a typed DataSet can be used in all places you could use a DataSet. The sample application page shown in the following code example uses two DataGrid controls, RecordingGrid and TrackGrid. You can use the typed DataSet, RecordingDto when setting the DataSource properties on the controls because a typed DataSet inherits from DataSet.
using System; using System.Data; using RecordingApplication.localhost; public class RetrieveForm : System.Web.UI.Page { private RecordingCatalog catalog = new RecordingCatalog(); // protected void Button1_Click(object sender, System.EventArgs e) { string stringId = TextBox1.Text; long id = Convert.ToInt64(stringId); RecordingDTO dto = catalog.Get(id); RecordingGrid.DataSource = dto.recording; RecordingGrid.DataBind(); TrackGrid.DataSource = dto.track; TrackGrid.DataBind(); } }
Tests
Because the typed DataSet is generated by tools in the .NET Framework, you do not need to write tests to verify that it functions correctly. In the following tests, you are testing that the Assembler class loaded the typed DataSet correctly.
AssemblerFixture.cs
using NUnit.Framework; using System.Data; using Recording; [TestFixture] public class AssemblerFixture { private RecordingDto dto; private RecordingDto.Recording recording; private RecordingDto.Track[] tracks; [SetUp] public void Init() { dto = Assembler.CreateRecordingDto(1234); recording = dto.Recordings[0]; tracks = recording.GetTracks(); } [Test] public void RecordingCount() { Assert.Equals(1, dto.Recordings.Rows.Count); } [Test] public void RecordingTitle() { Assert.Equals("Up", recording.Title.Trim()); } [Test] public void RecordingChild() { Assert.Equals(10, tracks.Length); foreach(RecordingDto.Track track in tracks) { Assert.Equals(recording.Id, track.RecordingId); } } [Test] public void TrackParent() { RecordingDto.Track track = tracks[0]; RecordingDto.Recording parent = track.Recording; Assert.Equals("Up", parent.Title.Trim()); } [Test] public void TrackContent() { RecordingDto.Track track = tracks[0]; Assert.Equals("Darkness", track.Title.Trim()); } [Test] public void InvalidRecording() { RecordingDto dto = Assembler.CreateRecordingDto(-1); Assert.Equals(0, dto.Recordings.Rows.Count); Assert.Equals(0, dto.Tracks.Rows.Count); } }
These tests describe how to access the individual elements of the DataSet. Because of the use of a typed DataSet, the test code does not require the actual column names and does not require the return type to be cast. Comparing these tests with the ones described in Implementing Data Transfer Object in .NET with a DataSet reveals the differences between using a strongly-typed interface and a generic interface. The strongly-typed interface is easier to use and understand. It also provides the added benefit of compile-time checking on return types.
Resulting Context
Implementing DTO with a typed DataSet shares a number of the same benefits and liabilities as implementing DTO with a DataSet; however, certain benefits and liabilities are unique to a typed-DataSet implementation.
Benefits
The typed DataSet shares the following benefits with a DataSet when used as a DTO:
Development tool support. Because the DataSet class is implemented in ADO.NET, there is no need to design and implement the DTO. There is also extensive support in Visual Studio for automating the creation and filling of DataSet and typed-DataSet objects.
Integration with controls. A DataSet works directly with the built-in controls in Windows Forms and Web Forms, making it a logical choice as a DTO.
Serialization. The DataSet comes complete with the ability to serialize itself into XML. Not only is the content serialized, but the schema for the content is also present in the serialization.
Disconnected database model. The DataSet represents a snapshot of the current contents of the database. This means that you can alter the contents of the DataSet and subsequently use the DataSet as the means to update the database.
An additional benefit that might persuade you to use a typed DataSet as opposed to an ordinary DataSet is the strongly-typed interface of the typed DataSet. A typed DataSet, as described here, generates classes that can be used to access the contained data. The classes present an interface which defines how the class is to be used in a more explicit manner. This removes the need for casting which was present in the DataSet implementation.
Liabilities
The typed DataSet shares the following liabilities with a DataSet when used in the context of a DTO:
Interoperability. Because the DataSet class is part of ADO.NET, it is not the best choice for a DTO in cases requiring interoperability with clients that are not running the .NET Framework.. You can still use DataSet, however, the client will be forced to parse the XML and build its own representation. If interoperability is a requirement, see Implementing Data Transfer Object in .NET with Serialized Objects.
Stale data. The typed DataSet, like a DataSet, is disconnected from the database. It is filled with a snapshot of the data in the database when it is constructed. This implies that the actual data in the database may be different from what is contained in the typed DataSet. For reading primarily static data, this is not a major issue. If the data is constantly changing, however, using any kind of DataSet is not recommended.
Potential for performance degradation. Instantiating and filling a DataSet can be an expensive operation. Serializing and deserializing a DataSet can also be very time consuming. A good rule of thumb for using a DataSet is that a DataSet is a good choice when you are using more than one table or relying on the capability of the DataSet to update the database. If you are displaying the results from a single table, then using a DataReader with strongly-typed objects may offer better performance. For more information, see Implementing Data Transfer Object in .NET with Serialized Objects.
The following are additional liabilities when using a typed DataSet as opposed to an ordinary DataSet:
A typed DataSet is still a DataSet. A typed DataSet can be substituted at runtime with a DataSet. This means that even though the strongly-typed interface exists, programmers can still access the data without the typed interface. A possible result of doing this is that there could be parts of the code which couple the application tightly to the DataSet table and column names.
The need for an XML schema. When using a typed DataSet you have to create and maintain an XML schema to describe the strongly-typed interface. Visual Studio .NET provides a number of tools to assist in this process, but nevertheless you still have to maintain an additional file.
Related Patterns
For more information, see the following related patterns:
Implementing Data Transfer Object in .NET with Serialized Objects.
Assembler. In Enterprise Application Architecture Patterns, Fowler defines Assembler as a specialized instance of the Mapper pattern [Fowler03].
Acknowledgments
[Beau02] Beauchemin, Bob. Essential ADO.NET. Addison-Wesley, 2002.
[Fowler03] Fowler, Martin. Enterprise Application Architecture Patterns. Addison-Wesley, 2003.
[Wildermuth01] Wildermuth, Shawn. "Typed DataSets in ADO.NET." .NET Developer. May 2001.