[Flex]Flex 开发架构渐变

mikel阅读(776)

Flex 无疑是RIA第一位得选择,而JAVA 可以是Enterprise application 的第一选择。 结合二者来开发Web App 无疑是一种走向流行的方案。 前端Flex+后端JAVA的简单架构如图:

flex and java

 

 

在实际得开发中实现上述结构的方法非常之多。我只是将自己开发的渐变过程记录下来。希望对后来者有所借鉴。

这个系列blog包括:

 

一。混沌未开-Flex-all-in-one

二。中央管理-Flex Central Managerment

三。MVC框架-Flex Cairngorm

四。咔嚓Front ControllerCairngorm

五。轮回转世-Mate

 

样例。

为简洁起见,用一个非常简单的样例来演示开发过程:密友列表

系统只有二个画面:

  登录-LoginView:

 

 login view

 

 

输入用户名和密码并登录, 进入密友列表画面(BuddyListView):

 

 buddylist

 

 

由于这个系列blog焦点在Flex应用开发方式,所以只选择Remote Object  作为和后端通讯的方式。AMF的实现使用Adobe 的opensource data service-BlazeDS。Java代码非常简单。仅限于配合这个blog系列。

相关得配置文件和JAVA class 如下:

1。remot-config.xml:

 

Xml代码
  1. <?xml version=”1.0″ encoding=”UTF-8″?>  
  2. <service id=”remoting-service”  
  3.     class=”flex.messaging.services.RemotingService”>  
  4.   
  5.     <adapters>  
  6.         <adapter-definition id=”java-object” class=”flex.messaging.services.remoting.adapters.JavaAdapter” default=”true”/>  
  7.     </adapters>  
  8.   
  9.     <default-channels>  
  10.         <channel ref=”my-amf”/>  
  11.     </default-channels>  
  12.     <destination id=”flexmvcRO”>  
  13.      <properties>  
  14.       <source>com.ny.blog.flex.mvc.accessor.DummyAccessor</source>  
  15.       <scope>session</scope>  
  16.       </properties>  
  17.      <adapter ref=”java-object” />  
  18.     </destination>  
  19.   
  20. </service>  

 

2.DummyAccessor.java:

Java代码
  1. package com.ny.blog.flex.mvc.accessor;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. import com.ny.blog.flex.mvc.pojo.Friend;  
  7.   
  8. public class DummyAccessor {  
  9.   
  10.  public DummyAccessor() {  
  11.  }  
  12.    
  13.  public boolean login(String userName,String password){  
  14.   return true;  
  15.  }  
  16.    
  17.  public  List<Friend> getAllFriends(String userName){  
  18.   List<Friend> myBuddy = new ArrayList<Friend>();  
  19.   Friend dummy1 = new Friend();  
  20.   dummy1.setFirstName(”John”);  
  21.   dummy1.setLastName(”Smith”);  
  22.   myBuddy.add(dummy1);  
  23.     
  24.   Friend dummy2 = new Friend();  
  25.   dummy2.setFirstName(”Andy”);  
  26.   dummy2.setLastName(”Jones”);  
  27.   myBuddy.add(dummy2);  
  28.     
  29.   Friend dummy3 = new Friend();  
  30.   dummy3.setFirstName(”Michael”);  
  31.   dummy3.setLastName(”Niu”);  
  32.   myBuddy.add(dummy3);  
  33.   return myBuddy;  
  34.  }  

 

3.相关  pojo Friend.java:

Java代码
  1. public class Friend {  
  2.  private String firstName;  
  3.  private String lastName;  
  4.  private String nickName;  
  5.   
  6. public Friend() {  
  7.  }  
  8.   
  9. //getter and setters  
  10. …  
  11. }  

 

 

Lets go :混沌未开-Flex-all-in-one

[架构]做人、做事,做架构师——架构师能力模型解析

mikel阅读(680)

要想从一名普通程序员发展成为优秀的架构师,“个人特性”与“技术技能”缺一不可;而“技术专业能力”、“人际关系能力”和“业务能力”更是优秀架构师重要的三种能力。

文 / 周爱民(《程序员》2008年4月刊)

引子

究竟是什么让你在同一个位置上——例如程序员或技术负责人——工作了三年、五年或者更久,而 仍然得不到任何的发展空间?你觉得自己已成为技术圈中的大牛,并信心满满地去拿明天就要颁发的某某大奖,然而却仍然停留在同样的技术职位上,去年到今年涨 的薪水甚至填不平物价升幅?于是,你开始对老板不满,对员工不满,对昨天升职的那个同事不满……你开始计划明天就要跑单,或者准备考虑提出加薪却又心怀忐 忑。

如果技术人员有发展的轨迹,那么他要么“看透工具的本质,把关注点转移到‘团队’的圈子里去 ”,要么“顺着代码铺就的道路,亦步亦趋地成为良匠大师”。仅以技术方向而言,你大概可以做到架构师、总架构师甚至首席架构师;但问题是:你现在还只是一 个程序员。那要如何才能踏上通往架构师之路呢?本文为你解析一个架构师的能力模型。

你能不能做一个好的架构师?

架构师不是界定一个技术高下的职位名称,而是一个职务。所谓职务,包括职——职位,务——工作。前者决定了你具备哪些资源,可以影响到怎样的范围,以及面向的机构,后者则简单地是你需要完成的工作列表。

所以我说“架构师”不是指“一个能做架构的人”。前者是把架构师当职能,后者是当工人。能做 一份工作列表中的事,并不等于就成为相应职位上的人。在管理体系里面,你的个人特性决定了你在哪个位置,而技术技能只是做事实施的必需。架构师这个职务, 同时要求较高的个人素质和技术能力,因此它的进取之路总结起来就是:做人、做事,做架构师。

因此“模型”由“个人特性”和“技术技能”两个方面构成,在第一张图中,我特别说明“个人特性”既包括人际关系的能力,也包括(具体)业务能力;“技术技能”也是如此。所以个人特性主要与“做人”有关,部分地也包含“做事”的要素。

(转)做人、做事,做架构师——架构师能力模型解析 - oliwen - oliwen

                                            图1 架构师能力模型

“有效沟通”以及“学会谈判”与做具体的事无关,是个人能力特性的公共方面。前者是过程,后 者是知道如何定目标与求结果。而“风险与防备”是做事过程控制的关键,与前面两项正好构成了一个做事基本能力的完整体系。基本上,这三项个人特性都是一个 “普通程序员”所不具备的,甚至在大多数情况下,普通程序员并不愿意去具备这样的个人特性,因为在许多陷于技术泥淖的开发人员看来:沟通总是会使事情变得 更加麻烦,谈判则徒耗时间而无济于事。然而事实上,在整个的架构决策过程中,架构师需要不停地沟通与谈判。将“架构”变成“决策”的过程,其实就是对各个 技术角色(及其思想)兼容并包的过程,你需要不断地协调需求、实现之间的各种问题,也需要面对各种投资者(时间、资金、人才等方面的决策者)进行谈判,以 确定项目的规模——没有规模也就没有范围,没有范围如何展开设计呢?

一部分开发人员会认为上述过程是“项目经理”的事情,但真的如此吗?当你作为一个更高级别的架构师,以至于要影响到多个项目的决策时,你就全然不会有这种感受了。因为这种情况下,你的决策将先于项目的启动,或者说你已经不单单是一个技术角色了。

设计是架构能力的一部分,但架构师不是设计师——看清楚二者之间的不同,你才真正迈出了架构师职业生涯的第一步。

抽象是思维能力、模型化是表达能力

个人特性中另一个非常重要的方面是“抽象思维”,而这是与架构师角色直接相关的一种能力。这种能力既有职业技能特征,又是普遍性的能力。

所谓普遍性的能力,是指“抽象”在我们——作为人这种个体的——生活中无处不在。例如我们说 花、草,说桌、椅……我们用语言去指称任何一个既已存在的(可以脱离我们的语言而自然存在的)事物时,就用到了抽象。说“桌子”的时候,既没有描述桌子的 具体形式,也没有说明它的规格,但我们用这个名词时,所有人都知道“桌子是什么”。所以,名词概念是整个抽象逻辑系统中的主体。如果失去了这些名词定义, 我们基本上不能说话,也不能描述任何东西——那便到了“只可意会不可言传”的境地。

用现有的成熟语汇去描述你的系统时,大多数人会理解你所表达的含义,例如我们说“这个系统设 计为一个三层结构”。然而架构师面临的系统在许多细节上并不见得能够用成熟的语汇去描述,因此必须自已构建一个抽象系统,这就需要概念抽象能力、概念表达 能力和基于概念的逻辑表达能力。

概念抽象能力是一种思维能力。简单地说,就是“把目标分解或概括清楚”:你要么概而言之“它 是什么”,要么详细地说明“它包括什么”。必须使用大量的语汇来陈述这个“什么”,这不单单是表达为文字,也表达为你在思想过程中的一个完整系统。通常用 的方法是“映射系统”。例如你可以用数学中的“数轴”来映射“实数域”。将目标系统形式化为一个概念化的、可讨论的结构系统后,你的抽象过程就基本结束 了。

(转)做人、做事,做架构师——架构师能力模型解析 - oliwen - oliwen

                                            图2 能力模型中的个人特性

然而这个“抽象系统”可能只构建在你的思维意识里,还必须把它描绘出来。因为不能只是你自己思考清楚,系统就能设计完成。这个“描绘”就依赖于后面两种表达能力,一种是描绘概念实体,一种是描绘实体上的逻辑——有趣的是,这似乎又回到了“程序=结构+算法”。

现在大家回过头来看看UML,或者更多种类的ML(建模语言),他们就用于表达这两个方面的东西:要么是概念实体(例如用一个框表明系统边界),要么是实体上的逻辑(例如用箭头表明逻辑时序)。

所以大家应该清楚,我们再如何称赞UML,它也只是一种对模型化系统的“表达能力”,你只能把它当一种辅助表达的工具去使用,它本身既不能帮助思考,也不见得能作为抽象过程中的或抽象思维环境中的参考。

任何一个优秀的架构师都有自己独特的思考方式,这决定了他如何抽象系统,以及如何“创造性地 ”设计与构画这个系统。这种“独特的思考方式”贯彻他从孩童开始的整个成长过程,直至他形成独立的社会观、人生观与世界观。他认识世界的方式和接受世界的 能力决定于他如何思考,也反映了他这种思考方式的“独特性”。但这并不表明他有特立独行的行为特性(我们这里只说他的思考方式),我们不应介意他是否用某 种语言(例如UML或者形式化编程语言)来表达他的思考结果。

推动:设计做大,实施做小

架构师首先是把问题的真正目标确定下来,然后变成系统设计、平台设计或架构设计。而在此之后 设计输出将会有两个方向的发展,一是被忠实地贯彻下来,二是被变形地发展下去。两个方向都存在致命的危险:架构最终能否被完整实现。对前者来说,可能是架 构设计过度,或设计本身出现了错误;后者则是对架构直接的伤害。

所以架构师必须参与实施的全程——尤其是在架构被映射为目标系统的前期。在这个阶段中,架构 师的任务就是推动架构实施,以保证在项目全程的设计/架构/体系的一致性。除了直接跟设计师或设计团队沟通,以保证他们的设计在你可以控制的范围之内以 外,架构师还必须有阶段化设计的能力。这种能力用于将一个原本规模宏大的架构设计,变成较小的、易于实施的、对开发团队来说可控的关键点。例如在体系层次 的规划上,设计可能是独立、异质的、可迁移的存储框架来实现数据层,但在(前期的)实施上,这里可能被表达为本地数据库,并要求前端开发人员必须通过一个 清晰的数据交互层来访问——例如一组数据存取接口,或一个独立数据服务组件。开发人员可能在这里遇到障碍:因为要通过这些中间层来访问本地数据库,纯粹是 多余的。然而,正是这“多余的工作”提供了系统弹性,为并行团队开发公共存储服务争取了周期,也为将来的灵活部署与数据迁移提供了可能。

这里的关键就在于,无论原始系统设定有多大,实施时总是在“做小”。每一个局部的实施块都是 可控的,并为它在整个体系空间中留下了位置和接口,这样才可能由“小的部分”做大。一个大系统的架构师可能同时在考虑许多个项目中的、不同位置的架构,并 且清楚这些项目最终的总体规模。而这,就是平台架构师和体系架构师所涉的领域。

(转)做人、做事,做架构师——架构师能力模型解析 - oliwen - oliwen

                                            图3 架构师模型图中的“实现能力”

架构真的是“好不好”的问题吗?如同我对工程的理解一样,架构问题的根本,也并不在于它是否 完美或漂亮,而是在于是否合用。因此架构师必须对实施架构的团队以及实施过程有充分了解,知道他们的能力缺陷,知道实现过程要消耗的资源,清楚每个环节可 能的故障以及先兆。只有这样,架构师才能设计一个让这个团队能实现,而且在实现过程中能受控的架构。

要知道,你作为架构师被请来,不是画几张图纸交给项目经理,说:你们去做吧,做不出来是你们 不会做。即使你可以身体力行,在这个团队中教大家、培养大家,那么公司的开销呢?风险呢?这些东西难道就不考虑了?项目的周期因为实现的复杂程度而无法控 制时,项目就死掉了。那么,追根究底来说,是不是架构师的问题?是啊,你为什么会做了一份“不合用”的架构呢?——你都不知道项目如何开发、由谁实施、如 何管理等等,又如何能面对这些实际环境去设计架构呢?

所以这一部分能力,是要在你的开发经验、团队经验以及用人识人的经验中去找的。参考模型图的“实现能力”下的“设计能力→了解你的主要沟通对象”和“架构推行”等分支,对你或有一些可用的提示。

局部与全局

架构是一个从全局到局部的过程,而实施正好反过来,是从局部到全局。这也正是“设计做大,实施做小”的另一个层面的含义。设计大才可以见到全局,才知道此全局对彼全局的影响;实施小才可能关注细节,才谈得上品质与控制。

事实上,大多数情况下架构是在为“当前项目之外”去考虑,这可以看成全局关注的一个组成部分。因此我们需要界定所谓“全局”的范围:超出公司或整个产品系列、产品线或规划的范围才是多余的。

所以当架构决策谈及“全局”时,其目标并不见得是“保障当前项目”,而又必须由当前项目去完成。

一个经常被用到的例子是:如果仅为当前项目考虑,那么只需要做成DLL模块;如果为产品线考虑,可能会是“管道+插件”的结构形式。而“管道+插件”的形式显然比做成DLL模块更费时,这个时间成本(以及其它成本)就变成了当前项目的无谓开销。

这种全局策略对局部计划的影响是大多数公司不能忍受的,也被很多团队所垢病。然而这却是架构 师角色对体系的“近乎必然”的影响——如果你试图在体系中引用架构师这个角色的话。一些情况下,体系能够容纳这种影响,例如“技术架构师”试图推动某种插 件框架,而正好开发人员对这项技术感兴趣,那就顺其自然地花点工夫去实现了。但如果不是这样,实施者或实施团队看不到“多余的部分”对他们的价值时,来自 局部的抵触就产生了。

这种情况下,平衡这些抵触就成了架构推行的实务之一。在我看来,“平衡”是全局的艺术和局部 的技术。也就是说,一方面架构师要学会游说,另一方面也要寻求更为简洁的、成本更小的实现技术。只有当整个体系都意识到(你所推行的)架构的重要性,而且 实施成本在他们可以接受的范围之内时,他们才会积极行动起来。

所以所谓平衡,其实也是折衷的过程。构架师只有眼中见大,才知道哪些折衷可以做,而哪些不 能。所谓设计评估(模型图中的实现能力->设计能力->设计评估分支)并不是去分析一个设计结果好或不好,而是从中看到原始的需求,看到体系 全局的意图,然后知道在将设计变得更为“适当”时可以做哪些折衷。同样的原因,架构师也必须知道自己的决策会产生的影响,才能控制它们,以防它们变成团队 的灾难。有些时候,架构师甚至需要抛弃一些特性,以使得项目能够持续下去。因为产品的阶段性产出只是整个战略中的一个环节,而不是全部。

其它

“怎么做一个架构师”这个问题得分成两个部分来看,一个是“做到”,一个是“做好”。由于架构师本身不过是一个技术职位,所以时机成熟了自然会做得到。但问题是,真有一天你被放在这个位置上了,你能做得好吗?

我浏览过几套所谓培训机构的有关架构师的教程,也翻阅过一些讲架构的书。我发现他们普遍地是 将架构作为一种“职业技术”来讲,就像培养程序员或者缝纫工一样来教育。但就我的经验来说,架构并不是一件纯粹表现技术能力的工作,所以并不是翻几本书学 几种方法就可以投入“实战”的。更深层的问题是,架构师其实不是“战”出来的。昨天跟同事讨论这个话题,他把我们这几年来的一些思考用了三句话来概括,非 常精彩:从无到有的,是架构;从表到里的,是抽象;从粗到细的,是设计。

那么到底什么是架构呢?从上面的概括中你是看不到答案的。到底如何做架构呢?从本文中你也是 看不到答案的。然而我说,“你看不到答案”的根源其实是在于你的眼光与心性——后面这个词换成现代白话,就是“思想”。真正阻碍了你成为优秀架构师的,也 许正是你既有的知识与思想方法,扔掉它们,接受一些全然有别的信息,也许正是良好的开端。

或许你现在正愤愤然:这篇文章怎么空洞无物?——我甚至能想象到一些读者的表情。然而请在问题面前停下来,不要急于给出答案。正如你将“?”稍微变下形,它就成为了“!”一样,问题的本身,就是答案。

作者简介

周爱民(aimingoo),具有十余年的软件开发、项目管理和团队建设的经验,现担任盛大网络的平台架构师,著有《大道至简》、《Delphi源代码分析》等。

 

原文地址: http://vipnews.csdn.net/newscontent.aspx?pointid=2008_05_30_150239242

[Python]Python开发web(1) -- 系统环境与框架的选择

mikel阅读(800)

学了多种语言,今天起把目标瞄向了Python和Perl。先从Python开始。

———————我是pangpang分隔线———————

官网上对Python的定义:

 

Python is a great object-oriented, interpreted, and interactive programming language. It is often compared (favorably of course  ) to Lisp, Tcl, Perl, Ruby, C#, Visual Basic, Visual Fox Pro, Scheme or Java… and it's much more fun.

 

Python combines remarkable power with very clear syntax. It has modules, classes, exceptions, very high level dynamic data types, and dynamic typing. There are interfaces to many system calls and libraries, as well as to various windowing systems. New built-in modules are easily written in C or C++ (or other languages, depending on the chosen implementation). Python is also usable as an extension language for applications written in other languages that need easy-to-use scripting or automation interfaces.

———————-我是pangpang分隔线———————

已搭建的系统环境:

CentOS 5.1 kernel 2.6.18

Python 2.5

 

———————我是pangpang分隔线———————

Python的流行框架有很多,纳入考虑范围的有django、pylons、web2py,另外,因豆瓣网而关注quixote。

 

排序原则

平台

有大把時間做企業級應用

plone,zope

適合 python 專家用

pylons, webpy, twisted.web, zope

追求一體框架

django, zope/plone, karingel

適合快速上手

karingel, cherrypy. turbogears

快速 CMS

django

支援度

django, turbogears, pylons, zope/plone

框架自由度

pylons, turbogears

一般用途

django, turbogears, pylons

文檔優勢

django, turbogears, pylons

有 Rails 背景

pylons, turbogears

有 AJAX/JavaScript helper/widgets

turbogears/pylons

WSGI 支持度

pylons, turbogears(django努力中)

JSON(AJAX server side)

turbogears

並用 flash/flex

turbogears

摘自:http://wiki.woodpecker.org.cn/moin/PyWebAppFrameworks

在比较后,决定使用pylons。

———————我是pangpang分隔线———————

相关链接:

Python  http://www.python.org/

Python wiki  http://wiki.python.org/moin/FrontPage

Python Tutorial  http://docs.python.org/tutorial/index.html

Learn Python in 10 minutes http://www.poromenos.org/tutorials/python

pylons  0.9.7  http://www.pylonshq.com

django  1.0.2  http://www.djangoproject.com/

web2py  1.5.7  http://mdp.cti.depaul.edu/

quixote  2.6  http://quixote.ca/

[C#]从零开始学习ASP.NET MVC(三) Controller/Action 深入解析与应用

mikel阅读(892)

一.摘要

一个Url请求经过了Routing处理后会调用Controller的Action方法. 中间的过程是怎样的? Action方法中返回ActionResult对象后,如何到达View的? 本文将讲解Controller的基本用法,  深入分析Controller的运行机制, 并且提供了创建所有类型Action的代码. 值得学习ASP.NET MVC时参考.

二.承上启下

在上一篇文章中, 我已经学会了如何使用Routing获取Controller和Action, 随后的程序会调用Controller中的Action方法.

每个Action方法都要返回一个ActionResult对象. 一个Action会将数据传递给View,如图:

image

三.Controller与Action的作用

1.职责

Controller负责将获取Model数据并将Model传递给View对象.通知View对象显示.

2.ASP.NET MVC中的Controller和Action

ASP.NET MVC中, 一个Controller可以包含多个Action. 每一个Action都是一个方法, 返回一个ActionResult实例.

ActionResult类包括ExecuteResult方法, 当ActionResult对象返回后会执行此方法.

下面分层次的总结Controller 处理流程:

1. 页面处理流程

发送请求 –> UrlRoutingModule捕获请求 –> MvcRouteHandler.GetHttpHandler() –> MvcHandler.ProcessRequest()

2.MvcHandler.ProcessRequest() 处理流程:

使用工厂方法获取具体的Controller –> Controller.Execute() –> 释放Controller对象

3.Controller.Execute() 处理流程

获取Action –> 调用Action方法获取返回的ActionResult –> 调用ActionResult.ExecuteResult() 方法

4.ActionResult.ExecuteResult() 处理流程

获取IView对象-> 根据IView对象中的页面路径获取Page类-> 调用IView.RenderView() 方法(内部调用Page.RenderView方法)

通过对MVC源代码的分析,我们了解到Controller对象的职责是传递数据,获取View对象(实现了IView接口的类),通知View对象显示.

View对象的作用是显示.虽然显示的方法RenderView()是由Controller调用的,但是Controller仅仅是一个"指挥官"的作用, 具体的显示逻辑仍然在View对象中.

需 要注意IView接口与具体的ViewPage之间的联系.在Controller和View之间还存在着IView对象.对于ASP.NET程序提供了 WebFormView对象实现了IView接口.WebFormView负责根据虚拟目录获取具体的Page类,然后调用 Page.RenderView().

四.ActionResult解析

通过上面的流程,我们知道了ActionResult对象在整个流程中的作用.ActionResult是一个抽象类, 在Action中返回的都是其派生类.下面是我整理的RC2版本中提供的ActionResult派生类:

类名 抽象类 父类 功能
ContentResult     根据内容的类型和编码,数据内容.
EmptyResult     空方法.
FileResult abstract   写入文件内容,具体的写入方式在派生类中.
FileContentResult   FileResult 通过 文件byte[] 写入文件.
FilePathResult   FileResult 通过 文件路径 写入文件.
FileStreamResult   FileResult 通过 文件Stream 写入文件.
HttpUnauthorizedResult     抛出401错误
JavaScriptResult     返回JavaScript文件
JsonResult     返回Json格式的数据
RedirectResult     使用Response.Redirect重定向页面
RedirectToRouteResult     根据Route规则重定向页面
ViewResultBase abstract   调用IView.Render()
PartialViewResult   ViewResultBase 调用父类ViewResultBase 的ExecuteResult方法.
重写了父类的FindView方法.
寻找用户控件.ascx文件
ViewResult   ViewResultBase 调用父类ViewResultBase 的ExecuteResult方法.
重写了父类的FindView方法.
寻找页面.aspx文件

目前ASP.NET MVC还没有提供官方的ActionResult列表.上面的列表是我在源代码中分析得出的.有些解释的可能不够清楚,请谅解.

下面我将列举各个ActionResult的实例.

五.实例应用

1.添加Controller

安装了ASP.NET MVC后, 在项目上点击右键会找到添加Controller项:

image

2.添加Action

下面这个类提供了返回各种类型的ActionResult的Action实例:

public class DemoController : Controller
{
/// <summary>
/// http://localhost:1847/Demo/ContentResultDemo
/// </summary>
/// <returns></returns>
public ActionResult ContentResultDemo()
{
string contentString = "ContextResultDemo!";
return Content(contentString);
}
/// <summary>
/// http://localhost:1847/Demo/EmptyResultDemo
/// </summary>
/// <returns></returns>
public ActionResult EmptyResultDemo()
{
return  new EmptyResult();
}
/// <summary>
/// http://localhost:1847/Demo/FileContentResultDemo
/// </summary>
/// <returns></returns>
public ActionResult FileContentResultDemo()
{
FileStream fs = new FileStream(Server.MapPath(@"/resource/Images/1.gif"), FileMode.Open, FileAccess.Read);
byte[] buffer = new byte[Convert.ToInt32(fs.Length)];
fs.Read(buffer, 0, Convert.ToInt32(fs.Length) );
return File(buffer, @"image/gif");
}
/// <summary>
/// http://localhost:1847/Demo/FilePathResultDemo
/// </summary>
/// <returns></returns>
public ActionResult FilePathResultDemo()
{
//可以将一个jpg格式的图像输出为gif格式
return File(Server.MapPath(@"/resource/Images/2.jpg"), @"image/gif");
}
/// <summary>
/// http://localhost:1847/Demo/FileStreamResultDemo
/// </summary>
/// <returns></returns>
public ActionResult FileStreamResultDemo()
{
FileStream fs = new FileStream(Server.MapPath(@"/resource/Images/1.gif"), FileMode.Open, FileAccess.Read);
return File(fs, @"image/gif");
}
/// <summary>
/// http://localhost:1847/Demo/HttpUnauthorizedResultDemo
/// </summary>
/// <returns></returns>
public ActionResult HttpUnauthorizedResultDemo()
{
return new HttpUnauthorizedResult();
}
/// <summary>
/// http://localhost:1847/Demo/JavaScriptResultDemo
/// </summary>
/// <returns></returns>
public ActionResult JavaScriptResultDemo()
{
return JavaScript(@"alert(""Test JavaScriptResultDemo!"")");
}
/// <summary>
/// http://localhost:1847/Demo/JsonResultDemo
/// </summary>
/// <returns></returns>
public ActionResult JsonResultDemo()
{
var tempObj = new { Controller = "DemoController", Action = "JsonResultDemo" };
return Json(tempObj);
}
/// <summary>
/// http://localhost:1847/Demo/RedirectResultDemo
/// </summary>
/// <returns></returns>
public ActionResult RedirectResultDemo()
{
return Redirect(@"http://localhost:1847/Demo/ContentResultDemo");
}
/// <summary>
/// http://localhost:1847/Demo/RedirectToRouteResultDemo
/// </summary>
/// <returns></returns>
public ActionResult RedirectToRouteResultDemo()
{
return RedirectToAction(@"FileStreamResultDemo");
}
/// <summary>
/// http://localhost:1847/Demo/PartialViewResultDemo
/// </summary>
/// <returns></returns>
public ActionResult PartialViewResultDemo()
{
return PartialView();
}
/// <summary>
/// http://localhost:1847/Demo/RedirectToRouteResultDemo
/// </summary>
/// <returns></returns>
public ActionResult ViewResultDemo()
{
//如果没有传入View名称, 默认寻找与Action名称相同的View页面.
return View();
}
}

在文章最后提供有完整实例代码下载.

六.Controller 深入分析

在研究Controller/Action的流程过程中, 发现了ASP.NET MVC一些问题.

1.Routing组件与MVC框架的结合

Routing组件和ASP.NET MVC并不是一个项目, 在ASP.NET MVC中仅仅是使用了Routing组件, 在源代码中是通过dll的方式引用的.Routing组件已经包含在.net framework 3.5 sp1中了.而ASP.NET MVC还未出正式版.

那么ASP.NET MVC是如何应用Routing组件的呢?

Routing组件获取了Url中的数据后, 会将数据保存在一个 RouteData 对象中.并将请求传递给一个实现了IRouteHandler接口的对象. 在Asp.net MVC中提供的MvcRouteHandler类实现了此接口, Routing 将请求传递给MvcRouteHandler的GetHttpHandler方法.下面是源代码:

IRouteHandler接口:

    public interface IRouteHandler
{
IHttpHandler GetHttpHandler(RequestContext requestContext);
}

 

MvcRouteHandler类:

    public class MvcRouteHandler : IRouteHandler {
protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext) {
return new MvcHandler(requestContext);
}
#region IRouteHandler Members
IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext) {
return GetHttpHandler(requestContext);
}
#endregion
}

 

曾经我认为IRouteHandler是多余的, 用IHttpHandler就够了. 现在知道了为何要定义这个接口. 主要是为了传递RouteData对象.GetHttpHandler方法需要一个RequestContext 对象.RequestContext 是 System.Web.Routing程序集中的类, 里面除了处理请求需要的HttpContextBase对象,还包括了一个RouteData对象.

RequestContext类:

    public class RequestContext
{
public RequestContext(HttpContextBase httpContext, RouteData routeData);
public HttpContextBase HttpContext { get; }
public RouteData RouteData { get; }
}

Routing组件在Web.Config中注册了一个HttpModule: System.Web.Routing.UrlRoutingModule, 而不是HttpHandler:

<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

 

可惜看不到这个类的源代码. 所有请求最后都是要传递给IHttpHandler对象处理, 主要的工作是编译页面, 所以我猜测这个Module将请求截获后通过IRouteHandler接口对象获取一个HttpHandler, 然后将处理移交给获取到的HttpHandler.

 

ASP.NET MVC 中实现了IHttpHandler接口的类是MvcHandler, MvcRouteHandler.GetHttpHandler方法就是返回一个MvcHandler对象. MvcHandler类的构造函数需要传入一个RequestContext对象. 实现的IHttpHandler接口方法处理过程中都需要依赖这个对象.

但是微软在这里的处理有一些不足. MvcHandler虽然实现了IHttpHandler接口但是不能被当作IHttpHandler接口使用. 因为IHttpHandler中没有定义RequestContext属性, 如果一个MvcHandler对象此属性没有赋值则会出错, 也没有将默认的无参数构造函数设置为private, 所以理论上可以很随意的实例化一个MvcHandler而不为其RequestContext属性赋值.

IRouteHandler想实现的语意是: 返回一个具有RequestContext属性的IHttpHandler对象.

但是最后的实现结果是: 提供"返回IHttpHandler对象"的方法,  此方法接收RequestContext对象参数.

还需要注意ControllerContext类. 在Controller的处理过程中使用此对象作为保存上下文数据的容器.下面是这几个类的包含关系:

image

可以看到在ControllerContext中包含了RequestContext对象,但是又将RequestContext对象中的两个属性 提取到自己的类中.如果仅仅是为了使用方便而这么做, 个人认为不是一个好的设计.数据对象的存储职责也应该明确,使用ControllerContext.RequestContext.RouteData 的方式更容易被人理解.

PS:这种方式类似于方法内联.对于属性JIT为了效率会帮助我们做内联.而仅仅是为了使用方便.

2.IView 与 View对象的关系

所以从系统的角度上看, 实现了IView接口的对象才是View.

但是从实现效果上看, 具体的aspx或者ascx页面才是View.

当第一次看到IView接口时我认为它应该是"View角色"需要实现的接口. 但是结果并不是这样.

在我们的系统中View对象应该是aspx或者ascx文件. 而且并不是所有的ActionResult都需要找到aspx或者ascx文件, 事实上只有PartialViewResult 和 ViewResult 才会去寻找View对象.其他的ActionResult要么是返回文件, 要么是跳转等等.

那么两者的关系到底是怎样的? 其实其中的过程需要牵扯到这几个接口和类:

IViewEngine, ViewEngineResult, ViewEngineCollection

ViewEngine是View引擎, ViewEngineCollection是一个引擎集合,里面保存了各种寻找View的引擎.但是在目前的源代码中只有 WebFormViewEngine : VirtualPathProviderViewEngine : IViewEngine

这一系列WebForm使用的引擎.引擎的作用有两个:

1.寻找Page/用户控件的路径

2.根据路径创建IView对象.也就是根据页面的物理文件创建IView接口对象.

而且目前实现了IView接口的对象也只有一个:

WebFormView

WebFormViewEngine 根据页面路径, 将一个页面地址转化为一个WebFormView对象,也就是一个IView接口对象.

至此IView接口和Page页面类仍然没有任何关系, IView对象只是保存了页面的物理路径.

接着在IView的Render事件中,根据物理路径创建了一个页面的object实例,注意看这一段代码:

            object viewInstance = BuildManager.CreateInstanceFromVirtualPath(ViewPath, typeof(object));
if (viewInstance == null) {
throw new InvalidOperationException(
String.Format(
CultureInfo.CurrentUICulture,
MvcResources.WebFormViewEngine_ViewCouldNotBeCreated,
ViewPath));
}
ViewPage viewPage = viewInstance as ViewPage;
if (viewPage != null) {
RenderViewPage(viewContext, viewPage);
return;
}
ViewUserControl viewUserControl = viewInstance as ViewUserControl;
if (viewUserControl != null) {
RenderViewUserControl(viewContext, viewUserControl);
return;
}

viewInstance 就是通过物理路径创建的页面对象.但是他的类型是object, 而且程序尝试将其分别转化为ViewPage对象和ViewUserControl对象.

我想很多人都看到了这里的设计不足.现在我们只能"约定": 所有的MVC中的页面对象都必须继承自ViewPage或者ViewUserControl类, 否则程序就会出错.产生这种不足的原因就是IView接口和ViewPage没有任何的耦合性, 完全是硬编码进去的.

为什么不让页面直接实现IView接口? 然后尝试将页面转化为IView接口对象, 而不是ViewPage, 这样才是好的设计. 其实微软知道什么是好的设计, 我猜测他们遇到的困难是Page对象和IView接口的冲突. 因为两者都需要Render. 如果在IView中定义自己的Render名称, 那就意味着ASP.NET MVC开发小组要自己处理页面的显示逻辑, 而现在ASP.NET WebForm模式下面的页面显示引擎又不能复用, 重新开发自己的一套显示引擎成本又太大, 才出此下策.

以上只是猜测.这种设计的缺陷虽然可以接受, 但是真的是让我好几天陷入了看不懂代码的痛苦之中.还好, 现在可以解脱了.

 

七.如何在MVC项目中使用MVC源代码项目

另外在为了跟踪实现过程, 我将ASP.NET MVC的源代码项目添加到了实例项目中, 其中有一些需要注意的地方:

1. 将实例项目中的System.Web.Mvc引用删除, 改成项目引用.

2. 需要在Web.Config中注释掉程序集引用:

        <compilation debug="true">
<assemblies>
<add assembly="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<add assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add assembly="System.Web.Abstractions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add assembly="System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<!-- <add assembly="System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>-->
                <add assembly="System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<add assembly="System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<add assembly="System.Data.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
</assemblies>
</compilation>

注释掉的程序集存在于GAC中, 但是我们现在不希望使用GAC中的程序集, 而是引用项目.

3. 将View目录下的Web.Config中的所有System.Web.Mvc相关的 PublicKeyToken 都修改为 null:

    <pages
validateRequest="false"
pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<controls>
<add assembly="System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" namespace="System.Web.Mvc" tagPrefix="mvc" />
</controls>
</pages>

八.总结

首先很抱歉在本系列文章开篇时承诺的每日一篇仅仅坚持了2天.具体原因就不解释了.这篇文章的出炉历时半个月, 并且经历了ASP.NET MVC版本从RC到RC2的演变. 在查看MVC源代码上花费了大量的时间, 希望付出的努力能够为大家研究学习ASP.NET MVC带来帮助. 我也会把这一系列的文章写完, 关于ASP.NET MVC还有太多的地方没有学习.

实例源代码下载地址:

http://files.cnblogs.com/zhangziqiu/Asp.net-MVC-3-Demo.rar

[Flex]FMS3系列(二):创建可交互的FMS连接--I can say:Hello World

mikel阅读(714)

  在做FMS开发中,flash客户端与FMS服务器通信交互数据等是常见的,比如flash客户端需要一播放一个视频,需要获得FMS发向flash端的一条消息等。那么我们要怎么才能实现flash客户端与FMS服务器建立可交互的连接、通信呢?

     本文将以flash客户端于FMS服务器通信为核心,以经典的"Hello World"示例详细介绍flash客户端于FMS服务器通信的实现。要实现两端通信,在客户端和服务器端都需要编码,一边发起通信请求和接收通信响应信 息(flash客户端),一端则提供接收请求进行业务处理等(FMS服务器端)。

     首先从flash客户端入手,本文的实例非常简单,要实现的功能就是flash客户端向FMS服务器端发起请求,调用FMS服务器上的一个方法,然后将FMS服务器上的方法返回值输出到控制台。

     flash端的开发可以有两种方式实现:Flash和Flex。本文会将这两种方式的实现都给出实例。首先看看Flash里的实现。
     启动Flash CS开发环境,新建立ActionScript 3.0的Flash文件,如下图:
              

     然后在上面新建立的ActionScript 3.0的Flash文件上,按F9进入动作面板(输入程序代码的地方,当然也可以将代码封装到单独的类文件里),如下图:             

      上图中已经将通过Flash开发连接到FMS服务器的代码全部贴出,代码很简单。NetConnection这个类在 Flash Player 和 Flash Media Server 应用程序之间或者 Flash Player 和运行 Flash Remoting 的应用程序服务器之间创建双向连接。

  通过NetConnection建立于FMS服务器的连接,然后使用NetConnection类的公共方法connect()通过RTMP协 议连接到指定的FMS服务器上指定的应用,如上图示为连接的FMS服务器上名为的“HelloWorld”的这个应用。如果对NetConnection 还不熟悉的朋友请先阅读下我的这系列文章的第一篇:《FMS3系列(一):第一个FMS程序,连接到FMS服务器(Flash/Flex两种实现) 》,随后通过调用call()方法调用FMS服务器上的方法,这里通过调用服务器上提供的sayHelloWorld()方法。

     Responder 类提供了一个对象,该对象在 NetConnection.call() 中使用以处理来自与特定操作成功或失败相关的服务器的返回值。详细见构造Responder对象的时候构造方法的参数,一个方法处理操作成功的逻辑,一个 方法处理操作失败的逻辑。
     OK,完成了上面的flash客户端的开发现在就只差FMS服务器端的开发了,FMS服务器理需要有一个通信文件来负责于flash客户端的连 接交互,通常情况下就是建立一个main.asc的通信文件。本文中的通信文件的程序代码非常简单,就是接受客户端的连接,然后提供一个客户端调用的方 法。完整代码入下:

1 application.onConnect = function(client)
2 {
3     client.sayHelloWorld=function(str)
4     {
5         return "I can say:Hello "+ str;
6     }
7       this.acceptConnection(client);
8 }

 

     通过上面的客户端和FMS服务器的开发,现在这样可以按Ctrl+Enter测试了,看看我们的flash小程序是否能够成功的连接到 FMS服务器上指定的HelloWorld,并成功调用服务器端指定的方法呢?打开FMS管理控制台可以看到如下截图效果。OK,我们的小程序已经成功的 连接到了FMS服务器上指定的应用(HelloWorld):

          
     下面是测试输出结果截图:
          

  上面的实现是直接将代码写在Flash中,我们也可以将代码提取出来形成ActionScript文件(类),只要该类文件继承于显示对象,通过Flash CS3的新特性设置舞台文档类就可以调用了,下面是提取为ActionScript类的编程实现:

 1 package
 2 {
 3     import flash.net.*;
 4     import flash.events.*;
 5     import flash.display.*;
 6     
 7     public class ClientCallServer extends Sprite
 8     {
 9         private var nc:NetConnection;
10         private var rs:Responder;
11         public function ClientCallServer():void
12         {
13             nc=new NetConnection();
14             rs=new Responder(onSuccess,onFailed);
15             nc.connect("rtmp://localhost/HelloWorld");
16             nc.client=this;
17             nc.call("sayHelloWorld",rs,"World");
18         }
19         
20         private function onSuccess(rs:Object):void
21         {
22             trace(rs.toString());
23         }
24         
25         private function onFailed(rs:Object):void
26         {
27             trace(rs.description());
28         }
29     }
30 }

 

  或许有的朋友已经习惯了使用Flex开发,喜欢用拖拽控件的方式来完成一些常用的功能,其实在Flex下开发和Flash差别不是很大,其实在编码层次上是没什么区别的,不同的只是界面的呈现方式不一样。

 1 private var nc:NetConnection;
 2 private var fmsServer:String="rtmp://localhost/HelloWorld";
 3 private var rs:Responder;
 4 
 5 private function initApp():void
 6 {
 7     nc = new NetConnection();
 8     nc.connect(fmsServer);
 9     nc.client=this;
10 }

  在Flex下开发,建立好mxml后可以直接在其内部的<mx:Script>组件里编写ActionScript代码,如上定义 了连接FMS服务器的NetConnection类的实例等。还定义了一个在Flex应用初始化的使用调用的方法initApp(),用来 完成flash客户端与FMS服务器的连接。

1 private function onClick():void
2 {
3     rs = new Responder(onSuccess,onFailed);
4     nc.call("sayHelloWorld",rs,"World");
5     nc.addEventListener(NetStatusEvent.NET_STATUS,onStatus);
6     nc.addEventListener(AsyncErrorEvent.ASYNC_ERROR,onAsyncHandler);
7 }

同Flash中开发一样,给Responder指定了成功和失败后的处理函数,详细如下:

/**
 * 通信成功并返回结果时被调度
 
*/
private function onSuccess(result:Object):void
{

    Alert.show(result.toString(),"调用结果");

}

/**
 * 通信失败并返回结果时被调度
 
*/
private function onFailed(result:Object):void
{
    Alert.show(result.description);
    Alert.show(result.code);
}

 

  如上就完成了Flex中调用FMS服务器并调用FMS上所提供的方法,服务器端的程序和前面 Flash中的一样。到此我们只需要调用onClick()方法就可以测试了,通过一个按钮组件来调用,如下:

<mx:Button x="91" y="219" label="Call" click="onClick()"/>

完整的Flex代码

 

  在平时的开发当中,要与FMS服务器创建可交互的连接有很多种方式,本文只是简单的介绍了最基本的一种调用,希望本文对想学FMS开发的朋友有所帮助。

 

版权说明

  本文属原创文章,欢迎转载,其版权归作者和博客园共有。  

  作      者:Beniao

 文章出处:http://beniao.cnblogs.com/  或  http://www.cnblogs.com/

推荐文章:http://www.cnblogs.com/aierong/archive/2009/01/15/fms3_main.html

[JQuery]模拟开心网消息提示

mikel阅读(758)

<script type="text/JavaScript">
$(document).ready(
function()
{
    setInterval(shine,
1000);
}
);
var shine=function()
{
    
//document.title = new Date().getTime();
    document.title = (document.title=='你有新的短消息'?'':'你有新的短消息')
}
</script>

[JQuery]jQuery UI 1.7 发布下载

mikel阅读(659)

JQuery 1.3.1发布之后,UI包一直没跟上,3月6日,兼容JQuery 1.3.1的UI包终于发布了。大家可以来这里下载jquery-ui-themes-1.7.zip,svn方式:http://jquery-ui.googlecode.com/svn/tags/1.7/themes/

 

这次改动主要如下:

[C#]并行编程的基础

mikel阅读(792)

并行编程在近些时候特别火爆,因为ILP得潜力已经被发掘得差不多了,TLP必然成为未来提高微处理器性能的最重要方向,最重要的体现形式就是多核并行处理器,看看做GPUNV前些日子的嚣张就知道多核并行运算的炙热程度。现在我们就来看看ILPTLP的转换中,我们程序员面临哪些可能的挑战。以下内容很多自己推测,肯定存在错误,仅仅作参考。

对于程序员来说,并行运算最重要的地方就是共享资源正确和高效的使用,而程序员所能最大限度掌控的便是存储系统。我们来看看INTEL多核CPU的构成原理图:
Core0 Excution > RFs > L1 Cache > L2 Cache > Memory > (Buffer) External Storage(HD)
Core1 Excution > RFs > L1 Cache >
其中红色部分为共享资源,下面我来详细讨论以下几个问题。

1.  Memory的使用策略
INTEL CPU对内存的使用策略多种多样,分别用来满足不同的应用需求

A. 强不可缓冲模式(strong uncacheable

B. 不可缓冲模式(uncacheable)

C. 写透模式(write through

D.写回模式(write back

E. 写组合(write combining

F. 写保护(write protection

我们常见的的两样就是DE,普通应用程序执行的内存模式都是WB的,AGP内存是WC的,而内存使用模式的定义可以通过PATMTTRs等进行配置,详细情况请参考相关手册。INTEL CPU按访问模式将数据分为3类:临时的,表示在不久马上就会用到的;连续的,表示数据会被序列访问的;非临时的,表示接下来一段时间不会被再次用到。WB内存模式最主要针对第一种使用模式的数据设计,经常被反复读写,所以WB模式会完整利用Cache来加速这样的访问。而WC模式主要是针对写的非常多,而基本不怎么读的数据,比如AGP MEMORY,这样数据就不必经过Cache缓冲,经过Cache反而会影响效率,因为同时要写Cache和内存,造成不必要的cache污染和cache波动。

对于WB模式内存区域具备如下特性:

1、  读取内存数据是投机执行的,不要指望内存读命令按程序顺序执行

2、  读可以提前到写之前执行,比如因为总线忙,写被BUFFERSTORE BUFFER中,而后续的读已经被CACHE,则读可以先进行。

3、  写内存通常都是遵循程序顺序的,但CLFLUSHNON-TEMPORAL指令除外,因为这些指令是WC语义的,WEAKING orDERNT写被BUFFERWC BUFFER中(通常为64BYTE)。

4、  写可被缓冲起来(CACHE中或者STORE BUFFER中)。

5、  WB内存绝对不会实行投机写。

6、  可执行存储转发(STORE FORWARDING

7、  读和写内存都不会被提前到I/O指令、LOCK指令和序列化指令之前。

8、  读不能提前到LFENCEMFENCE之前。

9、  写不能提前到SFENCEMFENCE之前。

2.  Cache的原理

INTEL CORE2实现了L1L2两级CACHEL2双核共用,CORE22CACHE都是64B/LINE,共1024行。分别是8路和16路组相连,CACHE在与主存之间传输数据采用8-Transfer Burst transcation,(CACHE LINE不支持partial write transaction)这个是总线技术术语,什么意思呢?就是一次传输64字节,分8组突发传送,为原子操作(毕竟我不是专业做硬件的,解释可能有误,详细请参看总线技术相关文档),即便只需要小于64字节的数据,总线依然传送64字节填充整个CACHE LINE。根据CPU的档次,L2 CACHE大小不一,但L1都是64KB的,32的指令,32的数据。两个CoreL1d Cache之间可以互相传输数据(可能与MESI协议实现有关),L1 Cache拥有几个数据和指令硬件预取器,L2 Cache的预取器是基于L1 Cache预取器的访问模式和密集程度来工作的,使用了一个改进的Round-Robin算法动态的在两个处理器之间分配带宽。前端总线接口也采用了类似的方式以确保平衡。L1 CacheL2 Cache采用了独立访问设计,也就是说Core可以直接从L2 L1Main Memory中直接取数据,无须逐级上升。intel cache使用了mainly inclusive设计。

现在我来详细讨论CACHE LINE的构造,如下图:

Data blocks

Tag

Index

Displacement

Valid bit

DATA BLOCKS包含实际从主存中攫取的数据64BTAG\INDEX\DISPLACEMENT均为内存地址,valid bit 好像是2bit用来表示此LINE的状态,后面我会详细叙述。可能朋友们看到这里对组相联这个概念还有些许模糊,其实这是对于CACHE的使用策略,我们知道CACHE远小于内存,如何合理高效的使用CACHE是个大问题,常用的算法有如下3中:

全相联:内存中的任何64对齐字节可以放在任何一CACHE LINE

直接映射:内存的任何一个64对齐字节只能放在特定的一CACHE LINE

N路组相联:内存的任何一个64对齐字节只能放在某些(NCACHE LINE

L18路组相联,表示每8CACHE LINE对应128个组值中的一个。7BIT的组值,6BITINDEX值,19BITTAG。很显然如果L1D32KB并且为8路组联,则每12864组组织重复一次。

 

我们详细理一下INTEL CORE2 L1 CACHE的参数:64KB64B/LINE8路组相联。所以我们可以知道CACHE LINE数目为1024行,每8行编为一组,共128组。CACHETAG SRAMDATA SRAM,每行都有一个TAG值,假设为所存数据物理地址的高19位,如下图TAG SRAM的组织:

Set Index

Way0

Way1

Way2

Way3

Way4

Way5

Way6

Way7

0

Tag

 

 

 

 

 

 

 

1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

127

 

 

 

 

 

 

 

 

CORE2可以一直读取8TAG同时比较。INDEX索引很显然是物理地址低位6BIT064),再取128的模,所以应该是[12:6]位为组索引,然后用要操作的地址的高19位与TAG SRAM中的128组中的每个值比较,一旦比较成功则CACHE HIT,这样我们便知道数据在哪组哪路。接下来便是数据的实际操作,L1 CACHE DATA SRAM好像是8BYTE 数据读宽度,一次可以READ 8路,还记得系统总线的8 TRANSFER BURST TRANSCATION吗?估计跟这也有关系.

上图可能有点问题(其实细节跟SRAM实现细节有关),但我们简单考虑,我们知道了HITSET数,以及SET中的路数,所以我们知道CACHE LINESET×8way+ Set_Offset,结合Data offset可以读取正确的数据出来。CORE2 使用CACHE的方式,我不知道具体情况,只知道INTEL CORE2 CACHE替换策略为PSEUDO-LRU算法,并且高端处理器CACHE HIT都使用虚拟地址完成,而不是物理地址,减少地址翻译负载。

3.  存储一致性维护

在此必须首先对CORE2双芯架构有个了解,为什么称其为双芯而不是双核,主要是因为CORE2 DUO的两个核是通过前端总线连接在一起的,导致不光CPU与外部设备访问要使用FSB,甚至CORE之间信息交流(MESI协议的实施)也要占用带宽,这是CORE2架构中最鸡肋的部分,当然在David Kanter以前的文章中提到L1 CACHE之间可以直接通信,可能是INTEL做了相关优化,但具体不得而知,暂时我们就当CORE只能通过FSB互相交互。每个CACHE LINE有一种状态,可以分别为MODIFIEDEXCLUSIVESHAREINVALIDMODIFIED默认就是EXCLUSIVE的,一般MESI协议会定义若干种同步消息来交流信息,而CORE都会在总线上监听SNOOPING这些消息,然后对自身的特定CACHE LINE的状态做修改。必须重点提醒的是所谓存储一致性主要是针对CACHEABLE MEMORY提出的,比如WTWB,而WC模式是无须硬件保证存储一致性的。以下是MESI协议中CACHE LINE根据自身状态和读写情况,进行自我状态改变,总线同步消息发送以及内存操作的图例,对理解MESI协议的实现非常重要。(贴不上图,随后补上).

4.程序编写中需要注意些什么

如何保证我们对存储器的访问是原子的?

很显然并行程序设计少不了进行同步操作,对临界区、时间、信号等同步资源的访问就必须是原子的。CPU提供了 3大类硬件功能供操作系统开发人员和应用程序开发人员来保证最基本的原子操作:1、硬件上真正不会被打断的指令。2、系统总线锁。3、CACHE一致性管 理。接下来我详细解释下以上3个功能。CORE2提供了一些保证不会被中断的指令,比如读或写位于对其位置的1/2/4/8字节长内存,如果内存没有被 CACHE,一次总线2字节的数据传输的访问也是原子的,CACHE LINE内数据访问都是原子的。因为CORE2的数据总线是4字节的,而访问指令只支持1、2、4字节访问,假设要访问的内存并没有对齐,就很可能需要2 次或2次以上总线数据传输才能完成反问,这样就又可能被打断了,比如访问位于地址3上的2个字节,这就需要2次总线操作,但如果访问的2个字节位于地址1 上就只需要一次,你可能会问,这明明没有对齐,怎么能一次传输搞定呢?因为这是CPU会利用总线宽度冗余,一次传输从0~3地址的4个字节,这样其中需要 的1、2字节也包含在里面了,但位于3上就不行了,因为不论总线是2字节还是4字节传送,都无法一次传输完毕,这与系统总线数据传输特性有关,只能对齐传 送数据!新人可能还会问个问题?操作寄存器的指令是否能被打断呢?我认为是不可以的,因为CISC指令的CPU将一条指令当作完整功能,能打断的只是外部 操作,比如数据LOAD和STORE,CPU内部一条指令解码后的所有微指令执行之间应该是无法被打断的,因为只有当一条指令的所有微指令都 retirement后,CPU的状态才算更新完毕。除非掉电,当然这个只是我的猜测,没有看到官方文档上有说明,知道的朋友可以告诉我。但这个问题对于 并行运算无关紧要,因为寄存器是CPU内部私有的,不是共享资源。总线锁,CPU有一个LOCK针脚,会触发LOCK信号,用来锁定系统总线(主要就是前 端总线)资源不被其他总线主控逻辑(如另外的核和BUS AGENT)占用,当一个核LOCK住系统总线后,其他核或总线代理都必须等待释放,这时外部中断什么的都无法传送到CPU中来。LOCK可以将外部储存 器访问原子化(因为其他主控逻辑都无法使用总线反问内存了),但细心的朋友可能会意识到一个问题LOCK只是用来锁定外部的系统总线,应该不能用来保证跨 CACHE LINE的内存访问吧,是的你想对了,我们无法保证这种操作的原子性,因为很显然CACHE是在CPU内部,不受LOCK信号影响,CORE2中如果访问 CACHE LINE的指令前加了LOCK前缀,是不会触发LOCK信号锁定系统总线的,而是会使用MESI协议保证CACHE一致性。任何需要1次以上存储访问的操 作都不是原子的,很可能被打断和中间安插其他访问指令,比如add [mem], eax,其实至少有2次存储访问,一次读,一次写,在SMP系统中就很可能在这2次存储访问之间加入其他存储指令,为了安全需要加LOCK前缀来保证一条 指令存储访问的原子性,这又涉及2种情况,CACHE内语义和总线语义,如果访问数据已经CACHE在高速缓冲中,则CORE2不会在总线触发LOCK信 号锁定总线。非对齐数据的存储访问也是非原子的,因为需要1次以上的存储访问,这就是为什么SMP系统中内存访问指令需要加LOCK的原因,如XADD和 CMPXCHG指令都需要多次存储访问,访问其他CORE同时访问数据,必须LOCK。而单处理器上我觉得XADD,CMPXCHG之流应该无需加 LOCK,注意这里的非原子有两种情况,一种是但处理器一种是多处理器,在单处理器上一条指令的执行是原子的,不论他需要访问几次存储 器,RETIREMENT标志着一条指令的执行完毕,指令的RETIREMENT是指令顺序的,但执行不一定是。所以单处理器不存在同时指令多条指令的问 题

_BEGIN:

PAUSE

Cmp [sem], 0 //测试锁

JNE _ BEGIN

Mov [sem], 1 //得到锁

DO SOMETHING

Mov [sem], 0 //释放锁

很显然以上程序是错误的,因为

Cmp [sem], 0 //测试锁

JNE _ BEGIN

Mov [sem], 1 //得到锁

中间是可以被打断的,多个线程轻松的可以同时得到锁。我们需要一条原子操作既完成比较又完成赋值,让我们看看cmpxchg,

Mov eax, 0

_BEGIN:

PAUSE

Cmpxchg [sem], 1

JNE _BEGIN

DO SOMETHING

Mov [sem], 0

很显然没问题,只要有其中一个线程进入,其他的线程都会碌碌无为在前面循环,但这只是在单核CPU上有效,对 于多核可就没这么幸运了,因为多核上可能同时执行Cmpxchg [sem], 1这条指令,这条指令至少有2次存储访问(不对齐可能就会有4次访问),一次是读sem,一次是写sem,不论sem在内存还是在cache中,2个核中 的4次访问可能互相交叉,A READ SEM,B READ SEM, A WRITE SEM, B WRITE SEM,很显然错了。如何避免这种情况呢,便是加前缀LOCK,触发总线锁定信号,这样其他核必须等待总线释放后才能访问特点内存地址,对齐数据访问都是 原子的,跨DATA BUS宽度、CACHE LINE和页边界的都很可能不是原子的。显然不是原子的情况都是需要1次以上存储访问的,不管是CACHE还是总线。

在TEMPORAL语意的MEMORY区域上执行NON-TEMPORAL STORE是否需要程序保证数据一致性?

回答是肯定的,单独提出这个问题的主要原因是存在大量的NON-TEMPORAL STORE优化,主要是MOVNTQ等指令,这些指令是NON-TEMPORAL语意的,跟WC BUFFER一样,使用write combining buffer进行写缓冲,并且写是WEAK orDERING的,顺序和结果都会在此BUFFER中合并,如果FSB是64BIT的,一般WC BUFFER也是64字节,分8个CHUNK,通过FSB的8-Transfer Burst transcation一次(原子的)将数据传输到内存控制器,如果WC BUFFER并没用写满,则需要通过多次(非原子的)partial write transaction完成。对WB内存进行NON-TOMPORAL STORE需要注意的问题,对于已经处于CACHE之中的内存,则遵循WB语义,如果不在则遵循WC语义。SFENCE不见得能把NT STORE的数据FLUSH到内存中,SFENCE貌似只对WC BUFFER和STORE BUFFER中的有用,这就是所谓的全局可见性,在CACHE和内存中都具备全局可见性,而CORE内部的REGISTER FILE都不是,这三条指令具备执行屏障和使前面存储访问指令全局可见的效果。

Core2中到底有哪些缓冲?

1、L1(I/D) L2  L3 CACHE

2、TLBs(I/D)translation lookaside buffer

3、Loop Buffer

4、Store Buffer

5、Write Combining Buffer

注意Trace Cache只有NetBurst架构的微处理器才具备,CORE2没有。

5.未来发展趋势

离我们最近的就是Nehalem架构的CPU CORE I7,应该说相当的先进,SHARE BUS 的FSB从此消失,迎来的是QPI互联的原生4核,集成内存控制器,PCI-E控制器和IOMMU单元,北桥即将消失,甚至连GPU集成也已经可在 INTEL技术线路图中出现,对于底层程序员还是会有一定影响。详细请参看 《Inside Nehalem: Intel's Future Processor and System》。

[C#]浅谈MVP与Model-View-ViewModel(MVVM)设计模式

mikel阅读(1541)

转载:http://www.cnblogs.com/xiaoyin_net/archive/2009/03/09/1407258.html    
  微软的WPF带来了新的技术体验,如Sliverlight、音频、视频、3D、动画……,这导致了软件UI层更加细节化、可定制化。同时,在技术层面,WPF也带来了

诸如Binding、Dependency Property、Routed Events、Command、DataTemplate、ControlTemplate等新特性。MVVM(Model-View-ViewModel)框架

的由来便是MVP(Model-View-Presenter)模式与WPF结合的应用方式时发展演变过来的一种新型架构框架。它立足于原有MVP框架并且把WPF的新特性揉合进去

,以应对客户日益复杂的需求变化。

      WPF的数据绑定与Presentation Model相集合是非常好的做法,使得开发人员可以将View和逻辑分离出来,但这种数据绑定技术非常简单实用,也是WPF所特有

的,所以我们又称之为Model-View-ViewModel (MVVM)。这种模式跟经典的MVP(Model-View-Presenter)模式很相似,除了你需要一个为View量身定制的

model,这个model就是ViewModel。ViewModel包含所有由UI特定的接口和属性,并由一个 ViewModel 的视图的绑定属性,并可获得二者之间的松散耦合,所以

需要在ViewModel 直接更新视图中编写相应代码。数据绑定系统还支持提供了标准化的方式传输到视图的验证错误的输入的验证。

如下图MVP设计模式架构所示。

                               

        在视图(View)部分,通常也就是一个Aspx页面。在以前设计模式中由于没有清晰的职责划分,UI 层经常成为逻辑层的全能代理,而后者实际上属于应用

程序的其他层。MVP 里的M 其实和MVC里的M是一个,都是封装了核心数据、逻辑和功能的计算关系的模型,而V是视图(窗体),P就是封装了窗体中的所有操

作、响应用户的输入输出、事件等,与MVC里的C差不多,区别是MVC是系统级架构的,而MVP是用在某个特定页面上的,也就是说MVP的灵活性要远远大于MVC

,实现起来也极为简单。

      我们再从IView这个interface层来解析,它可以帮助我们把各类UI与逻辑层解耦,同时可以从UI层进入自动化测试自动化测试(Unit/Automatic Test)并提

供了入口,在以前可以由WinForm/Web Form/MFC等编写的UI是通过事件Windows消息与IView层沟通的。WPF与IView层的沟通,最佳的手段是使用Binding

,当然,也可以使用事件;Presenter层要实现IView,多态机制可以保证运行时UI层显示恰当的数据。比如Binding,在程序中,你可能看到Binding的Source是

某个interface类型的变量,实际上,这个interface变量引用着的对象才是真正的数据源。

      MVC模式大家都已经非常熟悉了,在这里我就不赘述,这些模式也是依次进化而形成MVC—>MVP—>MVVM。有一句话说的好:当物体受到接力的时候,凡是有

界面的地方就是最容易被撕下来的地方。因此,IView作为公共视图接口约束(契约)的一层意思;View则能传达解耦的一层意思。

下面介绍一下MVVM设计模式。因为WPF技术出现,从而使MVP设计模式有所改进,MVVM 模式便是使用的是数据绑定基础架构。它们可以轻松构建UI的必要元素。

如,下图所示MVVM架构图。

                                

      可以参考The Composite Application Guidance for WPF(prism),prism V2下载源码

      View绑定到ViewModel,然后执行一些命令在向它请求一个动作。而反过来,ViewModel跟Model通讯,告诉它更新来响应UI。这样便使得为应用构建UI非常

的容易。往一个应用程序上贴一个界面越容易,外观设计师就越容易使用Blend来创建一个漂亮的界面。同时,当UI和功能越来越松耦合的时候,功能的可测试性就

越来越强。

      在MVP模式中,为了让UI层能够从逻辑层上分离下来,设计师们在UI层与逻辑层之间加了一层interface。无论是UI开发人员还是数据开发人员,都要尊重这个

契约、按照它进行设计和开发。这样,理想状态下无论是Web UI还是Window UI就都可以使用同一套数据逻辑了。借鉴MVP的IView层,养成习惯。View Model听

起来比Presenter要贴切得多;会把一些跟事件、命令相关的东西放在Controler里。

      参考示例:PersonViewModel层

public FamilyTreeViewModel(Person rootPerson)
{
    _rootPerson 
= new PersonViewModel(rootPerson);
    _firstGeneration 
= new ReadOnlyCollection<PersonViewModel>(
        
new PersonViewModel[] 
        { 
            _rootPerson 
        });
    _searchCommand 
= new SearchFamilyTreeCommand(this);
}

 在这里我不在赘述,详细应用实例参考:

Simplifying the WPF TreeView by Using the ViewModel Pattern

源码下载

[C#]Grove——.NET中的ORM实现

mikel阅读(1155)

作者:林学鹏

ORM的全称是Object Relational Mapping,即对象关系映射。它的实质就是将关系数据(库)中的业务数据用对象的形式表示出来,并通过面向对象(Object-Oriented)的 方式将这些对象组织起来,实现系统业务逻辑的过程。在ORM过程中最重要的概念是映射(Mapping),通过这种映射可以使业务对象与数据库分离。从面 向对象来说,数据库不应该和业务逻辑绑定到一起,ORM则起到这样的分离作用,使数据库层透明,开发人员真正的面向对象。图 1简单说明了ORM在多层系统架构中的这个作用。

art\grove_001.jpg

图1:ORM在多层系统架构中的作用

目 前大多数项目或产品都使用关系型数据库实现业务数据的存储,这样在开发过程中,常常有一些业务逻辑需要直接用写SQL语句实现,但这样开发的结果是:遍地 布满SQL语句。这些高藕合的SQL语句给系统的改造和升级带来很多无法预计的障碍。为了提高项目的灵活性,特别是快速开发,ORM是一个不错的选择。举 个简单的例子:在使用ORM的系统中,当数据库模型改变时,不再需要理会逻辑代码和SQL语句中涉及到该模型的所有改动,只需要将该模型映射的对象稍作改 动,甚至不做改动就可以满足要求。

*

本页内容
一、ORM的工具实现:Grove 一、ORM的工具实现:Grove
二、Grove在开发中的实际应用 二、Grove在开发中的实际应用
三、总结 三、总结

一、ORM的工具实现:Grove

优秀的ORM工具不仅可以帮助我们很好的理解对象及对象的关系,而且工具本身会帮助我们维护这些关系。基于这个理念,我设计了基于.NET的ORM工具——Grove orM Development Toolkit。

Grove orM Development Toolkit包含Grove和Toolkit两部分内容。Grove为ORM提供对象持久、关系对象查询、简单事务处理、简单异常管理等功能。数据持久 包括一些对象的Insert、Delete、Update、Retrieve等功能,关系对象查询则提供一些基于对象的复杂关系查询,包括对应到数据库功 能的子查询、关联查询(JOIN)、函数支持(count、avg、max、min)、聚合等。Toolkit是基于VS.NET 2002/2003的VSIP开发的外接程序,职责是帮助开发人员快速映射关系数据库中的业务模型到符合Grove要求的映射实体类,以及映射数据库中复 杂关系查询到Grove要求的关系映射实体,暂时只提供C#支持。图 2是Grove内部类实现关系图。

art\grove_002.jpg

图 2: Grove内部类实现关系图

在ORM实现的前期工作中,为了实现屏蔽各种数据库之间的操作差异,我们需要定义数据操作公有接口,封装基本的数据库Insert,Update,Delete,Query等操作。

public interface IDbOperator
{
int ExecNonQuery(string cmdText);
int ExecDataSet(string cmdText,DataSet entity);
object ExecScalar(string cmdText);
…
}

再定义一个数据库操作工厂类,实现各种不同类型数据的适配。

public abstract class DbOperatorFactory:IDbOperator

然后实现各种数据库的操作类,以SQLServer为例。

internal class SqlDbOperator:DbOperatorFactory

完成后,就是ORM主角——实体(Entity)的实现。ORM中实体的定义可以通过实体类自身包含数据模型元数据的方式实现,也可以通过定义XML的元描述实现。下面讲述了通过实体类自身映射的实现。

实 体(Entity)是实际业务数据的载体,包含业务数据模型的元描述,可以直接由数据库中的某张表或视图生成,也可以根据需要手工创建。.NET中提供了 System.Attribute,该类包含访问和测试自定义属性的简便方法。.NET Framework预定义了一些属性类型并使用它们控制运行时行为。我们可以通过继承System.Attribute基类自定义用于描述实体对象映射时 所需要的数据模型元数据,包括表名,字段名,字段长度,字段类型等一些常用的数据。

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
public class DataTableAttribute : Attribute

AttributeUsage用来表示该自定义属性可以被绑定在什么样的对象上,这里表示应用在Class或者Struct之上。

抽象一些具有相同特征的属性,使之成为自定义属性的基类。

[AttributeUsage(AttributeTargets.Property)]
public class BaseFieldAttribute:Attribute

定义一般字段所需要的自定义属性类。

[AttributeUsage(AttributeTargets.Property)]
public class DataFieldAttribute : BaseFieldAttribute

定义关键字字段所需的自定义属性类。

[AttributeUsage(AttributeTargets.Property)]
public class KeyFieldAttribute : BaseFieldAttribute

定义外键字段所需要的自定义属性类。

[AttributeUsage(AttributeTargets.Property)]
public class ForeignKeyFieldAttribute : BaseFieldAttribute

在以上自定义属性类完成后,我们需要一个用于访问实体在运行期绑定的自定义属性及属性数据的一个Help类。

internal class TypeHelper

实体定义完成后,我们需要根据实体类中绑定的自定义属性构造出运行期需要的SQL语句,为了收集实体类定义中的数据结构描述,我们需要定义一个类来说明实体在运行期所引用到的所有关于数据持久的信息,包括关键字字段,外键字段,一般字段等。

internal class TypeInfo

同时需要一个字段元数据描述类,描述字段在数据库中的名称,大小,是否可为空,列类型等信息。

internal class ColumnInfo

以上条件具备后,我们需要定义一个解析类,负责转换数据的程序类型到数据库字段类型,并且构造出Insert,Update,Delete,Query等操作所需要的SQL语句。

internal class SqlEntityParser

将上面的操作组合起来就是实体类对象操作员。

public class ObjectOperator

实现新增一个记录到数据库中,就是创建了一个新的实体对象,并交由对象操作员进行持久化。

public void Insert(object o)
{
TypeInfo info1=new TypeInfo(o.GetType());//根据实例或者实体描述信息
SQLCommand sc=info1.BuildInsertCommand(o);//构造SQL命令对象
DbOperator.Parameters=sc.Parameters;//赋值SQL命令所需的参数
DbOperator.ExecNonQuery(sc.CommandText);//执行SQL命令
}

这里的SQLCommand对象封装了SQL命令处理时所需要的一些值,包含SQL语句,命令参数(Parameter)等。

二、Grove在开发中的实际应用

安装Grove Kit要求Visual Studio 2003 及.NET Framework 1.1支持。从Grove网站下载安装包之后,解压缩GroveKit.zip,执行安装。

在GroveKit安装结束后,打开VS.NET,在VS.NET的启动画面上,您会看到Grove Develop Kit的标志,表示GroveKit已被正确安装。

2.1生成映射实体类

本文将以C# 项目为例解释Grove在开发中的具体应用。项目名WebApp1,操作系统 Windows 2000,数据库SQL Server 2000,数据库实例名:WebApp1,表结构定义如下:

表名 字段

Customers

CustomerID int(4) PK

CustomerName varchar(50)

CustomerDesc varchar(200)

Status tinyint

Addresses

AddressID int(4) PK

CustomerID int(4) FK

Address varchar(200)

1.

在 VS.NET中,打开“文件->新建->项目”,在Visual C#项目选择ASP.NET WEB应用程序,确定后生成WebApp1项目,在项目中添加对Grove.dll的引用,Grove.dll位于GroveKit的安装路径下,您也可 以通过.NET Configuration将Grove添加到程序集缓存中。

2.

在VS.NET中,打开“工具->Grove Tool Kit”,在GroveToolKit中设置数据库连接属性,并保存。

art\grove_003.jpg

图3 设置数据库连接串

3.

配置当前Web项目的web.config(在</configuration>之前加入以下配置)

<appSettings>
<add key="DBConnString" value="Server=localhost;Uid=sa;Pwd=sa;Database=WebApp1" />
</appSettings>

4.

4)在VS.NET解决方案资源管理器中选中Entities,并在GroveToolKit中选择表名,点击GroveToolKit的toolbar中的Preview Entity Class按钮,出现该表的实体映射类预览窗口。

art\grove_004.jpg

图4 预览实体映射类

5.

检查当前预览的实体类,点击生成文件按钮,该实体类将被生成到解决方案资源管理器当前选中的路径下。

6.

重复4,5步骤就可以生成其他表的映射实体类。

Customer.cs
using System;
using Grove.ORM;
[DataTable("Customers")]
public class Customer
{
int _CustomerID;
string _CustomerName;
string _CustomerDesc;
int _Status;
[KeyField("CustomerID")]
public int CustomerID
{
get{return this._CustomerID;}
set{this._CustomerID=value;}
}
[DataField("CustomerName")]
public string CustomerName
{
get{return this._CustomerName;}
set{this._CustomerName=value;}
}
[DataField("CustomerDesc")]
public string CustomerDesc
{
get{return this._CustomerDesc;}
set{this._CustomerDesc=value;}
}
[DataField("Status")]
public int Status
{
get{return this._ Status;}
set{this._ Status=value;}
}
}
Address.cs
using System;
using Grove.ORM;
[DataTable("Addresses")]
public class Address
{
int _AddressID;
int _CustomerID;
string _Address;
[KeyField("AddressID")]
public int AddressID
{
get{return this._AddressID;}
set{this._AddressID=value;}
}
[ForeignKeyField("CustomerID")]
public int CustomerID
{
get{return this._CustomerID;}
set{this._CustomerID=value;}
}
[DataField("Address")]
public string CustomerAddress
{
get{return this._Address;}
set{this._Address=value;}
}
}

代码1.实体映射类

2.2对象持久化

Grove提供ObjectOperator实现对映射实体对象的数据库持久工作,并通过IObjectQuery接口实现对复杂数据库关系映射实体的查询,主要接口如下:

方法 说明

Insert

新增一个对象

Update

根据条件更新一个对象

Remove

根据条件删除一个对象

RemoveChilds

删除所有关系对象

Retrieve

返回一个对象

RetrieveChilds

返回所有关系对象

GetDataReader

返回IDataReader

GetObjectSet

返回对象集合

GetObjectSource

根据对象定义返回DataSet

GetCount

从数据源返回记录条数

BeginTranscation

在数据库支持事务的基础上,开始事务处理

Commit

完成当前事务

Rollback

回退当前事务

2.3数据查询

如 一般的关系型数据库所具有的查询功能一样,Grove也有着非常丰富的查询功能,如对象查询、函数查询、子查询、排序查询等。这里对对象查询做简单介绍, 其它查询读者可以自行参考Grove的开发文档。Grove提供ObjectQuery 帮助ObjectOperator从数据源查询数据, ObjectOperator 需要通过ObjectQuery解析实体对象中的属性(System.Arrtibute)定义,并构造查询语句。ObjectQuery在运行时往往需 要定义筛选语句(请参考筛选语句的语法定义)。例如,检索Customer对象,当State 属性等于WA的情况:

ObjectQuery query=new ObjectQuery(typeof(Customer),"this.State='WA'");

当检索需要返回所有对象时,则不需要定义筛选语句

ObjectQuery query=new ObjectQuery(typeof(Customer),"");

2.4筛选语句的语法定义

在ObjectQuery中使用的筛选允许你在定义的时候,根据使用面向对象语法规则进行定义筛选语句。

操作 描述

!, not

用于比较布尔型,例如:

!Order.CustomerID.Contains(Customer.CustomerID)

<, >, <= , >=

用于值比较,例如:

Order.Quantity >= 12

=, !=, <>, = =

用于值判断,例如:

Customer.Country = 'USA' and Customer.Region != 'WA'

and, &&

用于逻辑判断,例如:

Customer.Country = 'USA' and Customer.Region = 'WA'

or, ||

用于逻辑判断,例如:

Customer.LastName = 'Smith' or Customer.LastName = 'Jones'

三、总结

以 上就是ORM的简单实现,复杂的关系对象映射及关系映射实体的查询也是ORM中尤为重要的一块处理,为了屏蔽各数据库之间的SQL差异,很多好的ORM框 架都提供一种符合面向对象语言本身语法规则的Query Language支持,例如实现对数据库函数的支持时,会通过定义一些公开的,与编程语言接近的语言来实现,比如说定义 Object.Size(),Object.Sum()等类方法式操作语法,在逻辑判断的时候提供一些语言本身的逻辑运算符支持,比如c#中 的&&表示and,||表示or等等这些一系列的面向对象编程风格的支持,都很好地为基于关系型数据库支持的系统开发向“面向对象”提供 了有力的支持。Grove目前对关系对象查询有很好的支持,感兴趣可以到Grove的网站了解详细信息。