• 创建:2006-10-14
  • 文章:24
  • 评论:20
  • 访问:4135
  •  
    原文地址:http://msdn.microsoft.com/zh-cn/library/ms954623.aspx

    Microsoft .NET Pet Shop 3.x: .NET Pet Shop 的设计模式与体系结构
    发布日期 : 4/1/2004 | 更新日期 : 4/1/2004

    Gregory Leake Microsoft Corporation

    James Duff Vertigo Software, Inc.

    2003 年 5 月

    适用于:

    Microsoft? .NET 框架 1.0 和 1.1 Microsoft? Windows 2000 和 Windows Server? 2003 Microsoft? Internet Information Services Microsoft? SQL Server? 2000 Oracle? 9i Database

    摘要:.NET Pet Shop 3.x 版针对 .NET Pet Shop 2.0 的评论者给出的重要反馈进行了改进,开发时确保了应用程序与 Microsoft 提出的体系结构指导文档保持一致。(20 页打印页)

    下载 Pet Shop 3.0 Installer.msi 代码示例.

    本页内容

    摘要 摘要
    Java Pet Store 是 什么? Java Pet Store 是 什么?
    Microsoft .NET Pet Shop Microsoft .NET Pet Shop
    业务需求 业务需求
    应用程序数据模型 应用程序数据模型
    .NET Pet Shop 2.0 体系结构 .NET Pet Shop 2.0 体系结构
    .NET Pet Shop 3.0 体系结构 .NET Pet Shop 3.0 体系结构
    小结 小结
    附录 A: 从版本 2 到版本 3 的更改 附录 A: 从版本 2 到版本 3 的更改

    摘要

    最 初研究 .NET Pet Shop 的目的是用 Microsoft .NET 实现 Sun 主要的 J2EE 蓝图应用程序 Sun Java Pet Store 同样的应用程序功能。 根据用 .NET 实现的 Sun J2EE 最佳实践示例应用程序,各方面的客户可以直接地对 Microsoft 的 .NET 技术与基于 J2EE 的应用程序服务器进行比较,同时了解构建基于Web的应用程序中用到的各种建议的设计模式之间的异同。 .NET Pet Shop 应用程序现在已经是第三版了,旨在显示构建企业级 n 层应用程序(可能需要支持多种数据库平台和部署模型)的 .NET 最佳实践。 根据社区对 .Net Pet Shop 2.0 的反馈,.NET Pet Shop 3.0 遵照 MSDN 上发布的 Microsoft《说明性体系结构指导》进行了重新设计。 第三版还完全符合了 Middleware 公司的应用程序服务器基准测试规范,将作为 Microsoft 参加今年春天即将进行的 Middleware Application Server Benchmark 的产品: 这是Middleware 公司举办的第二轮测试活动,旨在比较 .NET 和 J2EE 平台在构建和承载企业级 Web 应用程序方面的可伸缩性。

    Java Pet Store 是 什么?

    Java Pet Store 是按 Sun 公司维护的 J2EE 蓝图开发的分布式应用程序的一个参考实现。 示例应用程序最初的开发目的是帮助开发人员和架构师理解如何使用和利用 J2EE 技术,以及各个 J2EE 平台组件是如何配合的。 Java Pet Store 演示软件包括构建应用程序所需的Enterprise Java Beans (EJB) 体系结构、 Java Server Pages (JSP) 技术、标记库和 servlet 的完整的源代码及文档。 此外, Java Pet Store 蓝图应用程序还通过具体示例说明了一些模型和设计模式。

    完整的 Java Pet Store 包括三个示例应用程序:

    • Java Pet Store: J2EE 蓝图主应用程序。

    • Java Pet Store 管理器: Java Pet Store 的管理器模块

    • Blueprints Mailer: 在小一些的包中给出一些 J2EE 蓝图设计指南的一个小应用程序。

    Java Pet Store 的最初版本旨在处理以下数据库: Oracle、Sybase 和Cloudscape 。 IBM 已经开发了一个 DB2 版本的应用程序。 该应用程序可以从 Java 2 Platform Enterprise Edition Blueprints 公开获得。 主应用程序 Java Pet Store 是一个电子商务应用程序,可以通过它在线购买宠物。 启动应用程序后,可以浏览和搜索各种类型的宠物,从狗到爬行动物。

    使用 Java Pet Store 的典型会话方案如下:

    主页 — 这是用户第一次启动应用程序时加载的主页。

    类别查看 — 有五大类: 鱼、狗、爬行动物、猫和鸟。 每一类都有几个相关的产品。 如果选择鱼作为类别,可以看到天使鱼等等内容。

    产品 — 如果现在选择一个产品,应用程序将显示产品的所有类型。 通常产品类型是雄或者雌。

    产品详情 — 每种产品类型(分别用不同项目表示)有详细的视图显示产品说明、产品图像、价格和库存数量。

    购物车 — 用户可以通过它操作购物车(添加、删除和更新行项目)。

    结帐 — 结帐页面以只读视图显示购物车。

    登录重定向 — 当用户选择结帐页面上的“Continue”时,如果还没有登录,将重定向到登录页面。

    登录验证 — 通过站点的身份验证以后,用户被重定向到信用卡和记帐地址表单。

    定单确认 — 显示记帐地址和送货地址。

    定单提交 — 这是定单处理流程的最后一步。 定单现在将提交到数据库。

    图 1. Java Pet Store

    Microsoft .NET Pet Shop

    .NET Pet Shop 的目标是把注意力仅仅放在 Java Pet Store 上(管理和Mailer 组件没有在 .NET 中实现)。 除了重现 Java Pet Store 应用程序的功能之外,还增加了两项目标:

    • 比较 .NET 和 J2EE 通过最佳实践实现的真实应用程序中代码和代码大小上的异同。

    • 提供用 .NET 和 J2EE 实现的典型的设计良好的应用程序能够支持多少用户的数据。

    图 2. .NET Pet Shop

    .NET Pet Shop 的整体逻辑体系结构如图 3 所示,设计的中心是在表示层使用 ASP.NET Web 窗体,与逻辑中间层中的 C# 业务组件通信。 业务组件继而通过 ADO.NET 和 SQL Server 名为数据访问应用块 (DAAB) (可 以从此链接了解更多 DAAB 信息并下载完整的 DAAB 源代码)的帮助器类访问后端数据库。 数据访问功能完全抽象到数据访问层 (DAL) 中,与业务逻辑层 (BLL) 相分离。 .NET Pet Shop 3.0 中的新颖之处在于,我们为 Oracle 9i 和 SQL Server 2000 数据库都引入了 DAL 层。 相应 DAL 层的类加载将根据 Web.Config 中的应用程序配置设置在运行时动态生成。注意 .NET Pet Shop 3.0 使用了两个后端数据库,定单处理中要涉及跨两个数据库的分布式事务。 使用简单的 Web.Config 应用程序设置,用户可以对 .Net Pet Shop 进行部署,使用一个或者多个后端数据库,还可以自由地将 SQL Server 和 Oracle 后端数据库与由 .NET 服务的组件通过 COM+ 企业服务处理的分布式事务混合。

    图 3. .NET Pet Shop 高层逻辑体系结构

    图 4 说明了 Microsoft .NET Pet Shop 物理上是怎样部署的。 这里使用网络负载平衡 (NLB) 或者可能是硬件实现的负载平衡技术将入站的网络通信量分到了两台应用程序服务器上。 在网络请求达到群集中的一台机器时,针对该请求的所有工作都会在这台特定机器上进行。 业务逻辑和数据访问组件将以程序集的形式安装在两台服务器上,它们本质上是完全相同的。 如果负载平衡软件配置为使用“Sticky IP”,则每台服务器都有自己的会话-状态存储,因为要保证第二个请求返回到实现第一个请求的那台服务器。 如果解决方案所需的容错要求更高,两台应用程序服务器可以共享一个公共会话-状态存储比如 SQL Server 或者一台专用的会话服务器(图中没有显示)。 会话-状态存储的类型和位置由每个站点‘web.config’文件里‘system.web’元素‘sessionState’子节点中的值决定。

    图 4. .NET Pet Shop 的物理部署图

    业务需求

    作为 Pet Shop 3 体系结构文档的一部分,我们给出了 .NET Pet Shop 的业务需求,这样开发人员和客户就可以理解我们在做应用程序的设计决策时进行的一些选择。

    Pet Shop 应用程序的功能性需求是什么?

    • 应用程序应该使客户能够按类和通过关键字搜索浏览公司目录。

    • 应用程序应该为客户提供一种通过一个购物车模型就能购买多个商品项的机制。

    • 应用程序应该提供简单的安全模型,这样客户必须先进行登录,才允许购买购物车的内容。

    • 应用程序旨在支持高容量的企业级电子商务解决方案;因此应用程序应该展示以下方面:

    • 高性能,通过所支持用户数和用户响应时间进行衡量

    • 通过增加更多处理器来扩展的能力

    • 通过增加更多机器组成群集的分布式扩展能力

    • 在大型企业级系统中,应用程序可能需要访问多个数据库,因此应用程序应该支持分布式事务。

    • 应 用程序应该考虑灵活的部署策略。 默认时应用程序的设计方案是要部署到两台机器上,一台是应用程序服务器,一台是数据库服务器,但是应该能够扩展在其他部署模型下工作。 应用程序应该支持多个数据库供应商。 这里我们选择了 Microsoft SQL Server 和Oracle。

    • 应用程序应该容易维护,这是通过应用程序中的代码行数来衡量的。

    应用程序数据模型

    .NET Pet Shop 中使用的数据库架构是直接从 Java Pet Store 移植而来的。 Java Pet Store 支持几种数据库供应商格式,因此我们选取了 Sybase 应用程序的架构,并在一个 Microsoft SQL Server 2000 实例中创建。 这不需要改变 Sybase 版本的架构。 而创建 Oracle 版本的 .NET Pet Shop 时,我们直接采用了 Java Pet Store 数据库原来的 Oracle 实现。

    数据库 有如下整体表结构,参见表 1:

    表 1. Pet Shop 中的数据库表

    表名

    用途

    Account

    代表基本客户信息

    BannerData

    存储广告条信息

    Category

    目录类别( Fish, Dogs, Cats 等)

    Inventory

    产品库存状态

    Item

    各个产品的细节

    LineItem

    定单细节

    Orders

    客户下的定单。 定单包括一个或多个行项目

    OrderStatus

    定单状态

    Product

    目录产品,每个产品可有一或多类型(项目)。 通常类型可能是雄或雌。

    Profile

    客户的用户配置情况

    Signon

    客户登录表

    Supplier

    有关供应商信息

    在 .NET Pet Shop 版本 2 中,应用程序改为要创建一个方案,其中完成定单处理必须使用分布式事务。 为了适应分布式事务方案,Orders、OrderStatus 和 LineItem 表都分到不同的可能安装在不同机器上的数据库实例。 我们在 .NET Pet Shop 的第三版中保持了这个分布式设计模式。

    图 5. .NET Pet Shop 订购数据库架构

    图 6. .NET Pet Shop 帐号和产品数据库架构

    Pet Shop 表的设计可以做什么更改?

    应用程序中使用的架构可以做一些更改;然而,这些更改并不是为了与 Java Pet Store 参考实现提供的架构一致。 这些更改已列于表 2 中:

    表 2. Pet Shop架构中可能的改进

    更改

    原因

    表中不存储 HTML

    因为可能要使用不同客户端应用程序类型,数据库仅存储图像文件名而不是图像标记,部署客户端类型可以更灵活。

    对客户密码使用单向加密算法

    帮助使应用程序更安全,因为即使系统任何部分的安全受到威胁,读取密码仍然很困难。 这是要求设施必须重置密码为新值。

    加密信用卡信息

    在系统安全受到威胁时防治对信用卡信息的访问。 做出的其他更改还有将表设为只能允许通过一个存储过程进行写入访问;因此黑客访问数据库将不得不需要另一套凭据来读取数据。

    .NET Pet Shop 2.0 体系结构

    图 7. .NET Pet Shop 2 应用程序的体系结构

    .NET Pet Shop 2.0 被设计成部署在物理上两层的部署环境中,并且在应用程序的一些部分的实现中利用了这一事实。 应用程序由以下部分构成:一个用 ASP.NET Web 窗体 (用“代码隐藏”将应用程序 HTML 和用户接口代码分离)创建的 Web 层。 一个包含控制应用程序逻辑的业务组件(通过自定义版本的 Microsoft 数据库访问应用程序块 (DAAB) 与 SQL Server 数据库通信)的中间层。 为了支持分布式事务,一些中间层业务组件是用企业服务实现的。 对于 Microsoft .NET,这是一种支持分布式事务的建议方式。 然而,并非所有类都要扩展 ServicedComponent 类,因为将所有类都实现为企业服务的组件是有性能开销的。 发布第一次 Middleware 应用程序服务器基准测试中使用的 .NET Pet Shop 2.0 时,我们收到了许多反馈,认为体系结构应该优化,以更适应于大规模的企业。 反馈比较集中的方面包括:

    • 创建完全抽象的数据层,无需在中间层导入数据特定的类。

    • 为 Oracle 实现数据访问层,可以透明地使用与 SQL Server 版本一样的业务层和 UI 层。

    • 将 Web 会话状态从业务逻辑层和数据层中完全提取出来,这样应用程序的后端组件可以在物理上分布到 Web 服务器之外的其他计算机上,或者从其他类型的客户端比如基于 Windows的客户端和基于 Web– 的客户端重用。

    • 将应用程序模块整个分为多个命名空间和物理程序集。

    • 其他各方面的反馈。

    .NET Pet Shop 3.0 体系结构

    图 8. .NET Pet Shop 3.0 应用程序体系结构

    应用领域

    表 3. Pet Shop 解决方案中的应用领域

    范围

    用途

    .NET 实现

    用户接口组件

    捕获来自用户的数据输入,显示后端系统返回的数据。 它们还处理简单的定位。 参见用户接口组件。

    ASP.NET Web 窗体,用户控件和服务器控件。 这些构造能够清晰地分离设计者的 HTML 和 UI 代码比如按钮的事件处理程序。

    用户接口处理

    用后端业务对象控制用户定位和处理流程。 还要处理用户会话数据的管理。 参考用户处理组件。

    这些是用 C# 类实现的。 会话状态管理由 ASP.NET 处理。

    业务组件

    实现应用程序业务逻辑的组件

    这些是用 C# 类实现的

    业务实体

    在应用程序各层之间传递数据的瘦数据类。 参见业务实体组件。

    这些是用 C# 类实现的,每个字段都以属性的形式公开。 每个类都标记为“serializable”,启用进程间传输。

    数据访问层组件

    处理与后端数据存储区的交互,包括数据库、消息处理系统等。

    这些组件处理与后端数据存储区的交互,包括数据库、消息处理系统等,是用四个 C# 项目实现的:

     

     

    • 一组接口类,要公开的每个数据访问方法都有。

    • SQL Server 接口的实现。

    • Oracle 9i 接口的实现。

    • 一组加载正确实现的工厂类, SQL Server 或 Oracle。

    Microsoft Visual Studio .NET 解决方案

    图 9 显示了 Microsoft Visual Studio .NET 解决方案对 .NET Pet Shop 应用程序的布局。 应用程序的每个元素或层都有自己的项目,这样解决方案可以管理和清晰地定义应用程序中使用的新类应该放在哪里,旧类又可以在哪里找到。

    图 9. Visual Studio .NET 应用程序解决方案

    表 4 中列出了每个项目的目的:

    表 4. Pet Shop 解决方案中的 Visual Studio 项目

    项目

    用途

    BLL

    业务逻辑组件存放之处

    ConfigTool

    用来加密连接字符串和创建事件日志源的管理应用程序

    DALFactory

    用来确定加载哪一个数据库访问程序集的类

    IDAL

    每个 DAL 实现都要实现的一组接口

    Model

    瘦数据类或业务实体

    OracleDAL

    Oracle 特定的 Pet Shop DAL 实现,使用了 IDAL 接口

    Post-Build

    运行编译后操作的项目,比如将程序集添加到 GAC 或 COM+

    Pre-Build

    将程序集从 GAC 删除或从 COM+ 注销程序集的项目

    SQLServerDAL

    Microsoft SQL Server 特定的 Pet Shop DAL 实现,使用了 IDAL 接口

    Utility

    一组帮助器类,包括 DPAPI 的包装

    Web

    Web 页和控件

    Solution Items

    用来构建应用程序的杂项,比如用来签署应用程序程序集的 Pet Shop.snk 密钥文件

    数据库可移植性

    这 一版本 Microsoft .NET Pet Shop 的关键需求之一是提供支持 Oracle 和 SQL Server 数据库的应用程序实现。 在设计应用程序的数据库访问机制时,我们可以选择应该使用哪一个数据库提供程序;可以使用通用的 OLE-DB 托管提供程序或者数据库特定的优化了性能的 .NET 托管提供程序,比如 .NET 框架1.1 中提供的 SQL Server 和 Oracle 托管提供程序。 应用程序的关键需求之一是创建一个高性能的解决方案,因此我们选择用数据库本身的 .NET 托管提供程序构建应用程序。 关于托管提供程序和通用 OLE-DB 提供程序之间的性能差异分析,读者可以参考 Using .NET Framework Data Provider for Oracle to Improve .NET Application Performance, 该文档说明了厂商特定的提供程序能够比等价的 OLE-DB 提供程序性能好两到三倍。 在选择数据库特定的访问类时进行的考虑是,我们需要为每个要支持的数据库平台写一个单独的数据访问层,因此应用程序将包含更多代码。 虽然两个数据访问层共享很多公共代码,但还是要明显地分别针对具体数据库(Oracle 或 SQL Server 2000)。

    为了简 化数据库访问类的使用,我们选择 GoF (译注:指 Erich Gamma 等著《设计模式》一书)概述的工厂设计模式,通过反射动态在运行时加载正确的数据访问对象。 工厂设计模式是这样实现的: 创建一个 C# 接口,其中对于数据库访问类必须公开的每个方法都要声明一个方法。 对于每一个要支持的数据库,都创建一个实现数据库特定代码的具体类,以执行接口也称“协定”中的每一项操作。 为了支持运行时确定加载哪一个具体类,需要创建第三个类,也就是工厂类,它从配置文件中读入一个值以确定应该使用反射加载哪一个程序集。 通过 .NET 的反射命名空间,可以加载某个特定程序集并用该程序集创建某个对象的实例。 为了使应用程序更安全,为版本控制提供更好的支持,我们可以在应用程序配置文件(也就是这里的 web.config. )中添加要加载的程序集文件的“证据”,这意味着 .NET 框架将只加载我们在编译期间签过名而且有正确版本号的程序集。 图 10 说明了业务逻辑类、工厂类和数据库访问类是如何相互操作的。 这一创建的解决方案最重要的优势是数据库访问类可以在业务逻辑类之后编译,只要数据访问类实现了 IDAL 接口。 这意味着,如果要创建应用程序的 DB2 版本,我们不需要改动业务逻辑层(或者 UI 层)。 创建 DB2 兼容版本的步骤如下:

    1.创建 DB2 的数据库访问类,它应该实现 IDAL 接口。

    2.将 DB2 访问类编译成一个程序集。

    3.测试和部署新的数据程序集到一台运行中的服务器上。

    4.更改配置文件,指向新的数据库访问类。

    无需更改或重新编译业务逻辑组件。

    图 10. .NET Pet Shop 中 DAL 工厂类的实现

    存储过程

    通常我们都建议客户使用存储过程来访问数据库中的表。 原因如下:

    • 存储过程提供了封装查询的一种简洁机制。

    • 修改查询可以在不改变数据访问代码的情况下进行。

    • DBA 可以很容易地看到正在执行什么 SQL 语句。

    • 存储过程一般更安全,对数据库访问的控制也更容易。

    • 使用存储过程,可通过在存储过程中发送多个请求,避免与客户端的多次往返行程。

    • 存储过程与中间层生成的 SQL 相比,通常能提供最佳性能。

    • 存储过程提供了极好的封装 XML 查询和 XML 输入参数的方式。

    存储过程的缺点在于,它们往往是专有的,不能跨平台移植。

    然 而,要想最大程度地利用在数据库软件和硬件上已经花费的投资,开发人员往往对应用程序中使用的 SQL 针对具体数据库引擎进行优化,无论 SQL 是在存储过程中还是在中间层生成的。 这一点有一个很好的例子,就是唯一编号或者标识编号的生成,因为所有数据库执行此操作时都支持自己的特殊机制,所以用来生成唯一编号的 SQL 就往往是特定于所用数据库的。 一般总是有替代方案的,但是它们的执行速度都比不上专有解决方案。

    对于 .NET Pet Shop,我们有意识地没有在应用程序使用存储过程,因为这在 Middleware 基准测试中会被看作是 .NET 解决方案一种不太公平的优势。 实际上,这方面的性能差异很小,因为应用程序相对比较简单,大多数 SQL 语句的执行计划都缓存在数据库中了。 但是, Middleware 基准测试规范不允许使用存储过程,哪怕只是包装简单的 SQL 语句,因此 .NET Pet Shop 3.0 没有使用存储过程。

    缓存

    最有效的提高数据库驱动的应用程序性能的方式,是避免对每次请求都访问数据库。 ASP.NET 提供了各种缓存机制以提高大多数应用程序中的性能。 ASP.NET 中使用缓存的两种主要方式是输出缓存和数据缓存。

    .NET 缓存选项

    页 面级输出缓存接收来自 ASP.NET Web 页的响应,并将整个页面存入缓存中。 页面缓存被设计成工作在 Web 层和中间层之间,缓存中间层方法的结果/数据,或在两层应用程序中缓存数据库调用结果。 第一版的 .NET Pet Shop 同时提供了一个页面级输出缓存版本和一个非缓存版本。 第三版只支持数据缓存,但是可以很容易地改为支持输出缓存。 对于 Windows Server 2003 和 IIS 6.0,有些输出缓存的页面(那些 VaryByParm="none" 而且有 Cache 'Anywhere' 指令的)还能在内核级进行缓存,Internet 客户端访问就更快了。 无论如何,任何输出缓存的页面(内核或者非内核缓存)Windows 应用程序服务器都可以在资源 (CPU) 消耗少得多的情况下,极快速地进行服务,因为实际上重新创建页面无需进行处理。

    ASP.NET 输出缓存

    最 早的 .NET Pet Shop 应用程序,版本 1.5,还使用了一种页面级输出缓存的变种,也就是部分页面缓存或称片段缓存来缓存页面的不同区域。 例如,缓存每个页面顶部的头信息。 然而,头信息取决于正在登录的用户(因此两个不同版本的页面都要缓存)。 ASP.NET 很容易允许这种操作,使用‘OutputCache’指令中的 VaryByCustom 属性即可。 使用 VaryByCustom 需要重写 GetVaryByCustomString 方法以获取头信息的自定义缓存。

    ASP.NET 数据和对象缓存

    对 象缓存(缓存 API)允许使用 .NET 框架在内部缓存引擎中存储方法调用或者数据库查询的结果。 由于已经深入了应用程序工作管道,数据缓存可能无法像输出缓存那样提供同样的性能提升,因为对每个请求仍然必须动态构造 HTML 页面。 但是,通过在中间层存储非易失数据,已经在完全动态的页面和减少数据库负载之间取得了很好的折衷。 例如,要在两个 Web 页中以不同方式显示同样的数据,或者在同一个应用程序不同页面中以不同方式使用已经缓存的对象或数据。

    ASP.NET 缓存监视

    监 视 ASP.NET 缓存系统中发生了什么,有几种方式。 首要的方法是使用 Perfmon,但是还可以使用 SQL Server 跟踪检查访问数据库的时间,这根据具体情况而定。 为了在 Perfmon 中监视缓存,ASP.NET Application 性能对象下选择 Output Cache Entries 和 Cache API Entries 计数器,将它们添加到 Perform 图。 还可以在 Perfmon 中监视周转率和点击率,检查缓存中是否使用了某个项目。

    表 5. .NET 缓存选项摘要

    缓存类型

    优点

    限制

    输出缓存

    提供了最佳性能

    整个页面输出都缓存

    片段缓存

    (缓存用户控件)

    实现很简单。 整个页面输出都缓存

    有时间失效限制

    缓存 API

    页面中不同用户控件可以有不同的缓存超时

    缓存控件可以跨页面共享。 需要分别缓存每个用户控件

    Pet Shop Middleware 基准测试缓存规则

    Middleware 公司为基准测试应用程序定义了严格规则:什么能够缓存,怎样缓存。 大体而言,页面级输出缓存是禁止的,但是应用程序中的一些地方允许中间层数据缓存。 以下数据允许缓存,不需要每次请求都从数据库刷新: 类别信息,产品信息,项目信息(库存数据除外)和某些帐户信息。 对于库存数据,无论何时项目添加到购物车或者用户定位到‘ItemDetails’页面时,库存中的当前量应该反映最新值。 对于帐户信息,用户名和密码对于每一个登录企图都要进行验证,用作计帐信息的地址也应该始终从数据库刷新,以确保它在结帐处理中是最新的。 这里也就意味着,可以使用设置了给定期限的数据/对象缓存将大多数产品搜索和浏览操作的结果缓存在中间层中。

    基准测试的第二条规则是不应该允许页面级输出缓存;应始终要求 Web 服务器重新为页面创建要呈现的 HTML。 这是为了测试应用程序服务器生成动态页面的能力,而不是测试服务器从缓存拖出 HTML 有多快。

    Pet Shop 3.0 缓存实现

    对 于这一版本的应用程序,我们使用 ASPX 页面后代码中的数据缓存,来缓存中间层(业务逻辑层)请求的结果。 以下示例代码说明了如何访问 ASP.NET 缓存 API 从缓存检索信息。 该示例基于 Pet Shop 应用程序中的类别查询代码,category.aspx.cs。 在 Pet Shop 中,用户可以在五个预定义宠物类别中选择一个,查看该类别中的动物列表。 代码所做的第一件事是检查数据是否已经缓存,这是通过用类别 id 作为键查找数据缓存中的一个元素来实现的。 如果这个元素不存在,要么是因为数据还没有缓存,要么是当前缓存已经过期,将返回 null。 如果元素存在,就从缓存中拖出数据,并转换为合适的类型。 如果数据不在缓存中,调用中间层查询数据。 中间层查询的结果然后添加到缓存中,期限为从现在开始 12 小时。 或者,可以根据固定时间、对另一缓存项目的依赖,或者通过提供一个可以用来清除缓存的回调函数使缓存过期。

    			// Get the category from the query string
    string categoryKey =
    WebComponents.CleanString.InputText(Request["categoryId"],50);

    // Check to see if the contents are in the Data Cache
    if(Cache[categoryKey] != null){

    // If the data is already cached, then used the cached copy
    products.DataSource = (IList)Cache[categoryKey];

    }else{

    // If the data is not cached,
    // then create a new products object and request the data
    Product product = new Product();
    IList productsByCategory = product.GetProductsByCategory(categoryKey);

    // Store the results of the call in the Cache
    // and set the time out to 12 hours
    Cache.Add(categoryKey, productsByCategory, null, DateTime.Now.AddHours(12), Cache.NoSlidingExpiration , CacheItemPriority.High, null);

    products.DataSource = productsByCategory;
    }

    // Bind the data to the control
    products.DataBind();

    小结

    .NET Pet Shop 的体系结构已经进行了改进,能够在部署选择方面提供更灵活的解决方案,应用程序能够更加容易地进行自定义,适应业务模型中的变化。 尽管有所有这些变化,Pet Shop 的性能与 2.0 版实现大致相同,说明了 Microsoft .NET 框架在 J2EE 之外提供了另一种可行的企业级解决方案。 通过 .NET Pet Shop 和 J2EE Pet Store,架构师和开发人员可以使用功能完全一样、说明了各自平台上最佳编程实践的参考应用程序,一对一地比较 .NET 和 J2EE。 即将进行的 Middleware 基准测试将测试新的 .NET Pet Shop 3.0 实现,将比较它与两个新 J2EE 实现——一个基于 CMP 2.0,另一个基于纯粹的 JSP/Servlet 体系结构(不使用 EJB)的性能。 测试将由 Middleware 公司进行,在运行着各种 J2EE 应用程序服务器的服务器端发布。 将组成一个 J2EE 专家评委会监督这一基准测试,以确保对被测试产品的公平性以及所有实现都符合规范和最佳准则。 此外,已经邀请了主要的 J2EE 应用程序服务器供应商,加上 Microsoft 来参与这一基准测试,他们将对规范进行评价,提供供测试的实现,并现场进行微调和优化,参与测试过程。 Microsoft 选择全面参与第二轮测试。 可以到这里 了解 Middleware Application Server 测试第一轮的细节,测试基于两个基准测试应用程序:早期的 .NET Pet Shop 2.0 和一个基于 BMP 的 J2EE 实现,或者下载完整的报告

    附录 A: 从版本 2 到版本 3 的更改

    项目

    说明

    原因

    1

    创建数据库访问层 (DAL)。

    可以将业务逻辑从数据库访问代码中完全分离出来,因此可以无需更改业务逻辑代码,即可更换数据库供应商。

    2

    为所有瘦数据类(模型)创建公共的项目。

    模型项目只包含保存数据的瘦类,可以用在应用程序的每一层,作为传输数据的容器。所有模型类都通过 [Serializable] 标记支持序列化,以添加对群集和任何未来物理部署中变化的增强支持。

    3

    在 Components 项目中删除对 System.Web 的引用。

    这是一种好的设计实践,因为可以使中间层组件用于不同类型的 UI。

    4

    将一些自定义服务器控件改为 Web 用户控件;然而 Pager 控件仍然保留为自定义服务器控件。

    标头和标题控件含有许多 HTML/UI 内容,因此如果实现为 Web 用户控件更易维护。 Pager 控件处理的是查询字符串的操作,视图状态中数据的使用,因此作为自定义服务器控件更合适。

    5

    为 Oracle 创建了 DAL 实现。

    为了支持 Oracle 数据库,创建了特定的 Oracle DAL,可以使用 Oracle 特定的驱动程序

    6

    DAL 层现在实现了工厂模式 [GoF] 以加载相应的供应商特定的 DAL。

    为了隐藏后端所使用的数据库,使用工厂方法将接口返回到要用到的 DAL 层。

    7

    模型类中的所有公共字段都转换为属性。

    这样字段的存储机制就可以隐藏起来,如果要看什么函数修改了某些数据,这提供了一个很好的在代码中添加断点的地方。

    8

    创建数据库访问层 (DAL)。

    可以将业务逻辑从数据库访问代码中完全分离出来,因此可以无需更改业务逻辑代码,即可更换数据库供应商。

    9

    将所有静态方法改为实例方法。

    根据评论反馈进行的修改

    10

    将 assemblyinfo.cs 中的版本号改为与部署匹配的具体版本。

    在 DALFactory 对象中加载程序集时,允许指定证据。

    11

    在 Visual Studio .NET 解决方案中添加构建前和构建后的步骤。

    这样,在项目编译后,就可以对具体程序集运行 gacutil 和 regsvcs 实用工具。

    12

    将订购业务组件改名,根据其执行的功能而非实现机制。

    对其他开发人员而言理解组件的功能更直观。

    13

    创建配置工具辅助应用程序的设置。

    需要以管理员组成员的身份创建应用程序事件日志源。 确保完成最简单的方式是提供一个简单的工具,可以在部署后运行。

    14

    将代码修改为允许帐号和产品数据库以及定单数据库使用不同的 DAL。

    对用户请求的响应应该能够使用混合数据库部署模型。

    15

    页面中添加页面输出缓存;但是基准测试时要删除。

    有用户请求说明如何重写 VaryByCustom 函数使标题和标头控件等页面能够在 default.aspx 这样的页面中缓存。

    16

    将处理流程控件类添加到 Web 应用程序中。

    根据评论反馈做的修改,为帐号或购物车这样的 Web 区域提供单一位置来控制定位和状态管理。

    编辑 | 阅读全文(239) | 回复(0),seesky 发表于 2008-8-7 1:39

     http://www.022net.com/2008/8-5/442057152963066.html 转自人民网/天津视窗

     无论如何,索尔仁尼琴走了,良知仍在。良知何谓?那正是索尔仁尼琴所坚称的:“我绝不相信这个时代没有放之四海而皆准的正义和良善的价值观,它们不仅有,而且不是朝令夕改、流动无常的,它们是稳定而永恒的。” 

        1970年度诺贝尔文学奖获得者,享誉世界、被誉为“俄罗斯的良心”的俄罗斯作家亚历山大·索尔仁尼琴于8月3日在莫斯科逝世。 

        这个流亡一生的批判者,终生的持不同政见者,竟然能够在生命最后的时刻,安寝于自家的床上。而我们所不知道的是,当历史一声浩叹,这位享年89岁的老人永远阖上他的双目时,他在天的灵魂是否仍然注视着一切,仍然存在于“古拉格群岛”(索尔仁尼琴在《古拉格群岛》一书中,真实地再现了古拉格群岛劳改营的罪恶,展示了前苏联铁腕统治对人性的蔑视和摧残)之地,仍然温暖并激励着所有漂泊无依的人类的良心。但无论如何,即使他远去,他仍是一个在请求原谅的人,因为他“没有看到一切,没有想到一切,没有猜到一切”,而这样的一切,也许仍在一如既往地发生着。 

        他以批判者的方式深爱着自己的祖国,却不为当时的政权所宽容,而不得不半生漂泊。先是因对斯大林的不敬之词,索尔仁尼琴在苏联监狱中度过八年,接着又遭到流放。1962年他发表苏联文学中第一部描写斯大林时代劳改营的作品,引起轰动并受到赫鲁晓夫的赏识。但是随着赫氏下台,小说遭到批判。此后他的作品都无法在苏联公开出版。1967年他在苏联作家代表大会上散发公开信,抗议苏联的报刊检查制度,要求“取消对文艺创作的一切公开的和秘密的检查”。1969年他被苏联作协开除会籍。1974年因叛国罪被捕,并被驱逐出境,直到1994年在当时的俄罗斯总统叶利钦邀请下回到祖国。甫下飞机,面对欢迎的人群,他出人意料地俯下身来,用双手抚摸着故乡的泥土,沉痛地说:“我到这里向这块土地哀思,成千上万的苏联人当年在这里被杀害,并埋葬在这里。在今天俄罗斯迅速政治变革的时代,人们太容易遗忘过去的受害者。” 

        从来国家不幸诗家幸。但谁又能像索尔仁尼琴这样有幸,以他自身的经历与存在标志着一个时代的黑暗与变迁?他见证了一个政权的勃兴与倾覆,也正因此,曾任俄罗斯总统的普京这样说道:“全世界成百上千万人把索尔仁尼琴的名字和创作与俄罗斯本身的命运联系在一起。”他更以自己的方式证明政权并不等同于祖国。他不愿意将他对于祖国的爱,盲同于爱政权。他因此成为最伟大的爱国者。这是直到今天,他仍具有常识与启蒙意义的价值所在。上世纪八十年代末的一次民意调查显示,48%的俄罗斯人希望他回国担任总统。其实,正像索尔仁尼琴曾经说过的“一句真话比全世界的分量都重”这句话一样,对于世人来说,有一种叫做索尔仁尼琴的良知与坚守,比任何显赫的职位更加重要。历往总统有很多,索尔仁尼琴只有一个。或许对于一个国家或一个民族而言,永远为“总统”保有一名坚硬的批评者,是一个更值得庆幸的事情。 

        从斯大林到叶利钦、普京,索尔仁尼琴都是他们不得不面对的“俄罗斯的良心”。而怎样对待索尔仁尼琴,却显露出政权怎样的良知。对于邀请他回国的叶利钦,索尔仁尼琴毫无好感,曾经拒绝了叶利钦为他颁发安德烈·佩尔沃兹瓦内勋章;即使被邀请到俄罗斯国会演讲,他仍然率直地批评政府官僚机构膨胀、贪污舞弊盛行。以致2007年6月12日,俄罗斯前总统普京不得不“冒险”向索尔仁尼琴颁发2006年度俄罗斯国家奖“人文领域最高成就奖”,因为普京也并不能确定索尔仁尼琴是否同样会拒绝他的嘉奖。这一次,普京是幸运的,索尔仁尼琴接受了嘉奖。颁奖典礼结束后,普京前往莫斯科郊外的索尔仁尼琴家中拜访。坐在轮椅上的索尔仁尼琴为自己坐着迎接普京道歉。普京则表示,感谢作家同意会见他。普京说:“我想特别感谢您为俄罗斯所做的贡献,直到今天您还在继续自己的活动。您对自己的观点从不动摇,并且终生遵循。” 

        作为一个异见者,一个批判者,索尔仁尼琴或许并不需要从国家元首那里获得最高的评价,以此来证明自己的价值。但是,对于一个国家的元首来说,普京的确通过向一个异见者颁奖和作出上述评价,而获得了全世界的敬意。这是历经政权更替之后,我们所能发现的俄罗斯执政者的“良知密码”。我曾深深感动于普京拜访索尔仁尼琴的那张新闻图片:索尔仁尼琴坐在轮椅上,苍老、消瘦、宁静、平和。在他身后的门口,普京正步入室内,他的姿势仿佛生怕打扰了一位作家的思路。的确,在人类良知与终极价值面前,没有权势,没有职位,只有谦卑,只有敬畏。记得当时曾有舆论评价道:“昔日的特工和昔日的异议者,毕竟还拥有着共同的底线,或者说最低限度的共识。”这个底线与共识是什么?我想,至少应当包括对于一个作家自主创作权利的尊重,对于一个思想者自由思想权利的尊重,对于一个批判者独立批判权利的尊重。简言之,是对人类共同良知以及普世价值的尊重。 

        索尔仁尼琴之后,这个世界有没有更多的索尔仁尼琴?但是无论如何,索尔仁尼琴走了,良知仍在。良知何谓?那正是索尔仁尼琴所坚称的:“我绝不相信这个时代没有放之四海而皆准的正义和良善的价值观,它们不仅有,而且不是朝令夕改、流动无常的,它们是稳定而永恒的。”如果我们同样坚信,我们将同样获得并且拥有。(杨耕身)

    编辑 | 阅读全文(223) | 回复(1),seesky 发表于 2008-8-5 13:12

    2008-8-1 12:27 | SQL操作全集

    下列语句部分是Mssql语句,不可以在Access中使用。

    SQL分类:
    DDL—数据定义语言(CREATE,ALTER,DROP,DECLARE)
    DML—数据操纵语言(SELECT,DELETE,UPDATE,INSERT)
    DCL—数据控制语言(GRANT,REVOKE,COMMIT,ROLLBACK)

    首先,简要介绍基础语句:
    1、说明:创建数据库
    CREATE DATABASE database-name
    2、说明:删除数据库 
    DROP DATABASE dbname
    3、说明:备份sql server
    --- 创建 备份数据的 device
    USE master
    EXEC sp_addumpdevice 'disk', 'testBack', 'c:\mssql7backup\MyNwind_1.dat'
    --- 开始 备份
    BACKUP DATABASE pubs TO testBack
    4、说明:创建新表
    create table tabname(col1 type1 [not null] [primary key],col2 type2 [not null],..)
    根据已有的表创建新表:
    A:create table tab_new like tab_old (使用旧表创建新表)
    B:create table tab_new as select col1,col2… from tab_old definition only
    5、说明:删除新表drop table tabname
    6、说明:增加一个列
    Alter table tabname add column col type
    注:列增加后将不能删除。DB2中列加上后数据类型也不能改变,唯一能改变的是增加varchar类型的长度。
    7、说明:添加主键: Alter table tabname add primary key(col)
    说明:删除主键: Alter table tabname drop primary key(col)
    8、说明:创建索引:create [unique] index idxname on tabname(col….)
    删除索引:drop index idxname
    注:索引是不可更改的,想更改必须删除重新建。
    9、说明:创建视图:create view viewname as select statement
    删除视图:drop view viewname
    10、说明:几个简单的基本的sql语句
    选择:select * from table1 where 范围
    插入:insert into table1(field1,field2) values(value1,value2)
    删除:delete from table1 where 范围
    更新:update table1 set field1=value1 where 范围
    查找:select * from table1 where field1 like ’%value1%’ ---like的语法很精妙,查资料!
    排序:select * from table1 order by field1,field2 [desc]
    总数:select count * as totalcount from table1
    求和:select sum(field1) as sumvalue from table1
    平均:select avg(field1) as avgvalue from table1
    最大:select max(field1) as maxvalue from table1
    最小:select min(field1) as minvalue from table1
    11、说明:几个高级查询运算词
    A: UNION 运算符
    UNION 运算符通过组合其他两个结果表(例如 TABLE1 和 TABLE2)并消去表中任何重复行而派生出一个结果表。当 ALL 随 UNION 一起使用时(即 UNION ALL),不消除重复行。两种情况下,派生表的每一行不是来自 TABLE1 就是来自 TABLE2。
    B: EXCEPT 运算符
    EXCEPT 运算符通过包括所有在 TABLE1 中但不在 TABLE2 中的行并消除所有重复行而派生出一个结果表。当 ALL 随 EXCEPT 一起使用时 (EXCEPT ALL),不消除重复行。
    C: INTERSECT 运算符
    INTERSECT 运算符通过只包括 TABLE1 和 TABLE2 中都有的行并消除所有重复行而派生出一个结果表。当 ALL 随 INTERSECT 一起使用时 (INTERSECT ALL),不消除重复行。
    注:使用运算词的几个查询结果行必须是一致的。
    12、说明:使用外连接
    A、left outer join:
    左外连接(左连接):结果集几包括连接表的匹配行,也包括左连接表的所有行。
    SQL: select a.a, a.b, a.c, b.c, b.d, b.f from a LEFT OUT JOIN b ON a.a = b.c
    B:right outer join:
    右外连接(右连接):结果集既包括连接表的匹配连接行,也包括右连接表的所有行。
    C:full outer join:
    全外连接:不仅包括符号连接表的匹配行,还包括两个连接表中的所有记录。

    其次,大家来看一些不错的sql语句
    1、说明:复制表(只复制结构,源表名:a 新表名:b) (Access可用)
    法一:select * into b from a where 1 <>1
    法二:select top 0 * into b from a

    2、说明:拷贝表(拷贝数据,源表名:a 目标表名:b) (Access可用)
    insert into b(a, b, c) select d,e,f from b;

    3、说明:跨数据库之间表的拷贝(具体数据使用绝对路径) (Access可用)
    insert into b(a, b, c) select d,e,f from b in ‘具体数据库’ where 条件
    例子:..from b in '"&Server.MapPath(".")&"\data.mdb" &"' where..

    4、说明:子查询(表名1:a 表名2:b)
    select a,b,c from a where a IN (select d from b ) 或者: select a,b,c from a where a IN (1,2,3)

    5、说明:显示文章、提交人和最后回复时间
    select a.title,a.username,b.adddate from table a,(select max(adddate) adddate from table where table.title=a.title) b

    6、说明:外连接查询(表名1:a 表名2:b)
    select a.a, a.b, a.c, b.c, b.d, b.f from a LEFT OUT JOIN b ON a.a = b.c

    7、说明:在线视图查询(表名1:a )
    select * from (SELECT a,b,c FROM a) T where t.a > 1;

    8、说明:between的用法,between限制查询数据范围时包括了边界值,not between不包括
    select * from table1 where time between time1 and time2
    select a,b,c, from table1 where a not between 数值1 and 数值2

    9、说明:in 的使用方法
    select * from table1 where a [not] in (‘值1’,’值2’,’值4’,’值6’)

    10、说明:两张关联表,删除主表中已经在副表中没有的信息
    delete from table1 where not exists ( select * from table2 where table1.field1=table2.field1 )

    11、说明:四表联查问题:
    select * from a left inner join b on a.a=b.b right inner join c on a.a=c.c inner join d on a.a=d.d where .....

    12、说明:日程安排提前五分钟提醒
    SQL: select * from 日程安排 where datediff('minute',f开始时间,getdate())>5

    13、说明:一条sql 语句搞定数据库分页
    select top 10 b.* from (select top 20 主键字段,排序字段 from 表名 order by 排序字段 desc) a,表名 b where b.主键字段 = a.主键字段 order by a.排序字段

    14、说明:前10条记录
    select top 10 * form table1 where 范围

    15、说明:选择在每一组b值相同的数据中对应的a最大的记录的所有信息(类似这样的用法可以用于论坛每月排行榜,每月热销产品分析,按科目成绩排名,等等.)
    select a,b,c from tablename ta where a=(select max(a) from tablename tb where tb.b=ta.b)

    16、说明:包括所有在 TableA 中但不在 TableB和TableC 中的行并消除所有重复行而派生出一个结果表
    (select a from tableA ) except (select a from tableB) except (select a from tableC)

    17、说明:随机取出10条数据
    select top 10 * from tablename order by newid()

    18、说明:随机选择记录
    select newid()

    19、说明:删除重复记录
    Delete from tablename where id not in (select max(id) from tablename group by col1,col2,...)

    20、说明:列出数据库里所有的表名
    select name from sysobjects where type='U'

    21、说明:列出表里的所有的
    select name from syscolumns where id=object_id('TableName')

    22、说明:列示type、vender、pcs字段,以type字段排列,case可以方便地实现多重选择,类似select 中的case。
    select type,sum(case vender when 'A' then pcs else 0 end),sum(case vender when 'C' then pcs else 0 end),sum(case vender when 'B' then pcs else 0 end) FROM tablename group by type
    显示结果:
    type vender pcs
    电脑 A 1
    电脑 A 1
    光盘 B 2
    光盘 A 2
    手机 B 3
    手机 C 3

    23、说明:初始化表table1
    TRUNCATE TABLE table1

    24、说明:选择从10到15的记录
    select top 5 * from (select top 15 * from table order by id asc) table_别名 order by id desc
      
    随机选择数据库记录的方法(使用Randomize函数,通过SQL语句实现)
      对存储在数据库中的数据来说,随机数特性能给出上面的效果,但它们可能太慢了些。你不能要求ASP“找个随机数”然后打印出来。实际上常见的解决方案是建立如下所示的循环:
    Randomize
    RNumber = Int(Rnd*499) +1
     
    While Not objRec.EOF
    If objRec("ID") = RNumber THEN
    ... 这里是执行脚本 ...
    end if
    objRec.MoveNext
    Wend
     
      这很容易理解。首先,你取出1到500范围之内的一个随机数(假设500就是数据库内记录的总数)。然后,你遍历每一记录来测试ID 的值、检查其是否匹配RNumber。满足条件的话就执行由THEN 关键字开始的那一块代码。假如你的RNumber 等于495,那么要循环一遍数据库花的时间可就长了。虽然500这个数字看起来大了些,但相比更为稳固的企业解决方案这还是个小型数据库了,后者通常在一个数据库内就包含了成千上万条记录。这时候不就死定了?
      采用SQL,你就可以很快地找出准确的记录并且打开一个只包含该记录的recordset,如下所示:
    Randomize
    RNumber = Int(Rnd*499) + 1
     
    SQL = "SELECT * FROM Customers WHERE ID = " & RNumber
     
    set objRec = ObjConn.Execute(SQL)
    Response.WriteRNumber & " = " & objRec("ID") & " " & objRec("c_email")
     
      不必写出RNumber 和ID,你只需要检查匹配情况即可。只要你对以上代码的工作满意,你自可按需操作“随机”记录。Recordset没有包含其他内容,因此你很快就能找到你需要的记录这样就大大降低了处理时间。
    再谈随机数
      现在你下定决心要榨干Random 函数的最后一滴油,那么你可能会一次取出多条随机记录或者想采用一定随机范围内的记录。把上面的标准Random 示例扩展一下就可以用SQL应对上面两种情况了。
      为了取出几条随机选择的记录并存放在同一recordset内,你可以存储三个随机数,然后查询数据库获得匹配这些数字的记录:
    SQL = "SELECT * FROM Customers WHERE ID = " & RNumber & " OR ID = " & RNumber2 & " OR ID = " & RNumber3
     
      假如你想选出10条记录(也许是每次页面装载时的10条链接的列表),你可以用BETWEEN 或者数学等式选出第一条记录和适当数量的递增记录。这一操作可以通过好几种方式来完成,但是 SELECT 语句只显示一种可能(这里的ID 是自动生成的号码):
    SQL = "SELECT * FROM Customers WHERE ID BETWEEN " & RNumber & " AND " & RNumber & "+ 9"

      注意:以上代码的执行目的不是检查数据库内是否有9条并发记录。

     
    随机读取若干条记录,测试过
    Access语法:SELECT top 10 * From 表名 ORDER BY Rnd(id)
    Sql server:select top n * from 表名 order by newid()
    mysqlelect * From 表名 Order By rand() Limit n
    Access左连接语法(最近开发要用左连接,Access帮助什么都没有,网上没有Access的SQL说明,只有自己测试, 现在记下以备后查)
    语法elect table1.fd1,table1,fd2,table2.fd2 From table1 left join table2 on table1.fd1,table2.fd1 where ...
    使用SQL语句 用...代替过长的字符串显示
    语法:
    SQL数据库:select case when len(field)>10 then left(field,10)+'...' else field end as news_name,news_id from tablename
    Access数据库:SELECT iif(len(field)>2,left(field,2)+'...',field) FROM tablename;
     
    Conn.Execute说明
    Execute方法
      该方法用于执行SQL语句。根据SQL语句执行后是否返回记录集,该方法的使用格式分为以下两种:
        1.执行SQL查询语句时,将返回查询得到的记录集。用法为:
        Set 对象变量名=连接对象.Execute("SQL 查询语言")
       Execute方法调用后,会自动创建记录集对象,并将查询结果存储在该记录对象中,通过Set方法,将记录集赋给指定的对象保存,以后对象变量就代表了该记录集对象。

        2.执行SQL的操作性语言时,没有记录集的返回。此时用法为:
        连接对象.Execute "SQL 操作性语句" [, RecordAffected][, Option]
          ·RecordAffected 为可选项,此出可放置一个变量,SQL语句执行后,所生效的记录数会自动保存到该变量中。通过访问该变量,就可知道SQL语句队多少条记录进行了操作。
          ·Option 可选项,该参数的取值通常为adCMDText,它用于告诉ADO,应该将Execute方法之后的第一个字符解释为命令文本。通过指定该参数,可使执行更高效。

    ·BeginTrans、RollbackTrans、CommitTrans方法
    这三个方法是连接对象提供的用于事务处理的方法。BeginTrans用于开始一个事物;RollbackTrans用于回滚事务;CommitTrans用于提交所有的事务处理结果,即确认事务的处理。
      事务处理可以将一组操作视为一个整体,只有全部语句都成功执行后,事务处理才算成功;若其中有一个语句执行失败,则整个处理就算失败,并恢复到处里前的状态。
      BeginTrans和CommitTrans用于标记事务的开始和结束,在这两个之间的语句,就是作为事务处理的语句。判断事务处理是否成功,可通过连接对象的Error集合来实现,若Error集合的成员个数不为0,则说明有错误发生,事务处理失败。Error集合中的每一个Error对象,代表一个错误信息。
    编辑 | 阅读全文(235) | 回复(0),seesky 发表于 2008-8-1 12:27

    2008-7-31 22:44 | 北京欢迎你-人物, 地点

    迎接另一个晨曦 带来全新空气——陈天佳(正阳门箭楼上)

    气息改变情味不变 茶香飘满情谊——刘欢(鸟巢)

    我家大门常打开 开放怀抱等你——那英(德胜门箭楼,2008年4月13日)

    拥抱过就有了默契 你会爱上这里——孙燕姿(北海公园白塔,2008年4月2日)

    不管远近都是客人请不用客气——孙悦(普渡寺,2008年4月7日)

    相约好了在一起 我们欢迎你——王力宏(中华世纪坛、书法,2008年3月20日)

    我家种着万年青 开放每段传奇——韩红(北京大学未名湖畔博雅塔)

    为传统的土壤播种 为你留下回忆——周华健(太庙,2008年4月8日)

    陌生熟悉都是客人请不用拘礼——梁咏琪(国子监琉璃牌坊)

    第几次来没关系 有太多话题——羽泉(皮影戏)

    北京欢迎你 为你开天辟地——成龙(八达岭长城,2008年4月3日)

    流动中的魅力充满着朝气——任贤齐(琉璃厂北京画店、折扇)

    北京欢迎你 在太阳下分享呼吸——蔡依林(奥林匹克水上公园)

    在黄土地刷新成绩——孙楠(国家大剧院)

    我家大门常打开 开怀容纳天地——周笔畅(水立方)

    岁月绽放青春笑容 迎接这个日期——韦唯(糊风筝)

    天大地大都是朋友请不用客气——黄晓明(奥林匹克水上公园,2008年4月13日)

    画意诗情带笑意 只为等待你——韩庚(画京剧脸谱)

    北京欢迎你 像音乐感动你——汪峰(古观象台)

    让我们都加油去超越自己——莫文蔚(社稷坛(中山公园)五色土)

    北京欢迎你 有梦想谁都了不起——谭晶(四合院模型)

    有勇气就会有奇迹——陈奕迅(天坛坛门)

    北京欢迎你 为你开天辟地——阎维文(五棵松体育馆)

    流动中的魅力充满着朝气——戴玉强(北京孔庙大成门)

    北京欢迎你 在太阳下分享呼吸——王霞 李双松(什刹海荷花市场)

    在黄土地刷新成绩——廖昌永(首都博物馆)

    北京欢迎你 像音乐感动你——林依轮(茶道)

    让我们都加油去超越自己——张娜拉(鼓楼上,背景为钟楼)

    北京欢迎你 有梦想谁都了不起——林俊杰(湖广会馆大戏楼)

    有勇气就会有奇迹——阿杜(湖广会馆大戏楼)

    我家大门常打开 开放怀抱等你——容祖儿(故宫)

    拥抱过就有了默契 你会爱上这里——李宇春(火锅)

    不管远近都是客人请不用客气——黄大炜(拨浪鼓)

    相约好了在一起 我们欢迎你——陈坤(福到)

    北京欢迎你 为你开天辟地——谢霆锋(故宫)

    流动中的魅力充满着朝气——韩磊

    北京欢迎你 在太阳下分享呼吸——徐若瑄(世贸天阶,2008年4月7日)

    在黄土地刷新成绩——费翔

    片中:长城、天安门、天坛祈年殿、九龙壁、故宫三大殿、抖空竹、长嘴壶茶艺、北京烤鸭、拉面、首都机场、北京城铁、立交桥、体育场馆

    我家大门常打开 开怀容纳天地——汤灿(刺绣)

    岁月绽放青春笑容 迎接这个日期——林志玲(故宫午门) 张梓琳(包饺子)

    天大地大都是朋友请不用客气——张靓颖(剪纸)

    画意诗情带笑意 只为等待你——许茹芸(浇花) 伍思凯 (瓷器)

    北京欢迎你 像音乐感动你——杨坤(画桌前) 范玮琪(中央电视塔)

    让我们都加油去超越自己——游鸿明 腾格尔 黄大炜 满文军 纪敏佳(老北京四合院)周晓欧(书法)

    北京欢迎你 有梦想谁都了不起——沙宝亮(瓷器)

    有勇气就会有奇迹——金海心 何润东(中央电视塔)

    北京欢迎你 为你开天辟地——飞儿(北海公园五龙亭) 庞龙

    流动中的魅力充满着朝气——李玉刚(国家体育馆)吴克群(老北京四合院)

    北京欢迎你 在太阳下分享呼吸——5566(白塔寺) 胡彦斌 (老北京四合院)

    在黄土地刷新成绩——刀郎(老北京四合院)

    北京欢迎你 像音乐感动你——纪敏佳 屠洪刚 吴彤(老北京四合院)

    让我们都加油去超越自己——郭容 刘耕宏(老北京四合院)

    北京欢迎你 有梦想谁都了不起——金莎 苏醒 韦嘉(老北京四合院)

    有勇气就会有奇迹——付丽珊 黄征 房祖名(老北京四合院)
    编辑 | 阅读全文(328) | 回复(1),seesky 发表于 2008-7-31 22:44

    this article is coming from Scott's blog: http://weblogs.asp.net/scottgu/archive/2008/02/28/first-look-at-using-expression-blend-with-silverlight-2.aspx 

     


     

    Last week I did a First Look at Silverlight 2 post that talked about the upcoming Silverlight 2 Beta1 release.  In the post I linked to some end-to-end tutorials I've written that walk through some of the fundamental programming concepts behind Silverlight and WPF, and demonstrate how to use them to build a "Digg Search Client" application using Silverlight:

    Part 1: Creating "Hello World" with Silverlight 2 and VS 2008

    Part 2: Using Layout Management

    Part 3: Using Networking to Retrieve Data and Populate a DataGrid

    Part 4: Using Style Elements to Better Encapsulate Look and Feel

    Part 5: Using the ListBox and DataBinding to Display List Data

    Part 6: Using User Controls to Implement Master/Details Scenarios

    Part 7: Using Templates to Customize Control Look and Feel

    Part 8: Creating a Digg Desktop Version of our Application using WPF

    In this first set of Silverlight tutorials I didn't use a visual design tool to build the UI, and instead focused on showing the underlying XAML UI markup (which I think helps to explain the core programming concepts better).  Now that we've finished covering the basics - let's explore some of the tools we can use to be even more productive.

    Expression Blend Support for Silverlight

    In addition to releasing the upcoming Beta1 of Silverlight 2, we are also going to ship Visual Studio 2008 and Expression Studio tool support for targeting it.  These tools will offer a ton of power for building RIA solutions, and are designed to enable developers and designers to easily work on projects together.

    In today's post I'm going to introduce some of the features in the upcoming Expression Blend 2.5 March preview.  After demonstrating some of the basics of how Blend works, we are going to use it to build a cross-platform, cross-browser Silverlight IM chat client:

    The above screen-shot shows what the application looks like at runtime on a Mac.  Below is a screen-shot of what it looks like at design-time within Expression Blend:

    We'll use Expression Blend to graphically construct all of the UI for the application, as well as use it to cleanly data-bind the UI to .NET classes that represent our chat session and chat messages.

    Click here to download a completed version of this sample.

    All of the controls we'll use to build the chat application are built into Beta1 of Silverlight 2.

    Disclaimer: I am not a designer (nor am I cool)

    Let me say up front that I am a developer and not a designer.  I'm also not very cool.  While I understand the techniques to create UI, I sometimes choose bad colors and fonts when putting it together (only after I did all the screen-shots for this post did a co-worker helpfully point out that there is actually a site dedicated to banning some of the fonts and colors I used. Ouch).

    For those of you with artistic skill out there - please be gentle with me and focus your attention on the features and techniques I demonstrate below, rather than on the font and color choices I use. :-)

    Getting Started: Creating a new Silverlight 2 Project

    Expression Blend and Visual Studio 2008 share the same solution/project file format, which means that you can create a new Silverlight project in VS 2008 and then open it in Expression Blend, or you can create a new Silverlight project in Expression Blend and open it in VS.  You can also have both Expression Blend and VS 2008 open and editing the same project as the same time.

    Since in my previous Silverlight tutorial series I already showed how to create a new Silverlight project using VS 2008, let's use this post to show how to create a new Silverlight application using Expression Blend.  To do this, simply choose File->New Project in Expression Blend, select the "Silverlight 2 Application" icon, and click ok:

    This will create a new (VS-compatible) solution file and Silverlight application project:

    Blend includes a full WYSIWYG designer for Silverlight 2 applications.  When opening Silverlight pages and controls you can switch the design-surface to be in design view, a XAML source view, or a split-view that shows both the design view and XAML source view at the same time (and which supports live edits of both).  Above we are using the split-view option.

    Understanding Some Basics: Adding Controls to the Surface

    Expression Blend has a slightly different tool palette then Visual Studio (it more closely resembles what you'd find in a design tool like Photoshop). 

    Blend supports vector graphic editing:

    Blend also supports adding and working with controls.  There is a special icon on the Toolbox for layout controls (Grid, Stack, Canvas, Border, ScrollViewer, etc), text controls (TextBox, TextBlock, etc), and an icon that displays the controls you've recently used:

    Clicking on the final ">>" icon on the tool palette displays all of the controls that are available to be used:

    Make sure to click the "Show All" checkbox in the top-right hand corner of the Asset Library if you don't see the control you are looking for.  You can also use the "search" textbox to filter the controls by name.

    Important: Blend supports a design experience for all controls (both the built-in ones as well as any custom control or user control that your application references).

    Once you select a control from the toolbox, you can click and drag on the design-surface and draw out the control.  You can also drag controls from the asset tool onto the artboard.  By default you get automatic rules and positioning placement markers when you add and interact with the controls on the design-surface (below is a form with the built-in button, calendar and slider control on it):

    Understanding More Basics: Working with Control Properties

    You can select any object on the design-surface and then click on the "properties" panel on the right-hand side of the screen to customize its properties:

     

    Above I'm changing the "Background" brush of the button to be a deeper blue gradient (the third tab circled in red under the "Brushes" node allows us to configure the gradient brush). 

    Useful Tip: The properties window includes a search box near the top that you can optionally use to filter the visible property names:

    Because all UI objects in Silverlight and WPF are composed using vector graphics, we can shape/stylize/transform controls however we want.  For example, we could either set the "Transform" properties on our Button control or click on the corner edges of it to rotate/skew/scale it:

    This gives us a lot of power and flexibility to quickly and easily customize the experience however we want:

    Useful Tip: You can zoom in and out of the design surface by holding down the ctrl key and then use the wheel of your mouse to control the zoom depth.  You can then move the viewable region of the design surface by holding down the space bar, which will cause a hand-cursor to display, and then you can hold down the mouse and use it to drag the currently visible region around the screen.  This later tip is useful when you are zoomed way in and want to easily move the visible content around.

    Building our Chat Application: Defining the Layout

    In Part 2: Using Layout Management of my previous Silverlight tutorial series I talked about the layout management system within Silverlight and WPF, and how we can use layout panels to easily control application layout and flow.  Expression Blend makes defining layout rules easy, and includes built-in tool support for using these layout panels.

    Remember that our goal in building our chat application is to have UI that looks like this:

    To do this we'll start by defining a three row layout on our page.  We'll do this by hovering the mouse over the left margin of the design-surface and then click where we want to establish a new row definition (below I've already setup a top row definition - the cursor location circled in red indicates where I'll click to add a second row definition):

    Clicking on the top-left corner of the design surface (circled in red below) allows us to toggle whether the design surface is in Canvas layout mode or Grid layout mode. 

    When in Grid layout mode Blend will show us whether a particular row or column has a fixed width, or whether it is proportional to the size of the control.  Above the "empty locks" indicates that the three rows are currently proportional to each other (meaning they will all increase proportionally if we resize the browser to get bigger):

    If we click the top and bottom locks we can set those rows to have a fixed height instead, and leave the middle row to fill the remaining height. 

    One last step we can take is to click on the top margin and define a right-hand column as well - which we'll set to have a fixed width (and leave the left column to dynamically resize):

    Once we do the steps above, our XAML file with have a Grid defined like so:

    Useful Tip: Above we have a fixed width and height set for our Silverlight application (notice the Width and Height attributes on the root element).  We can cause the application to instead have a dynamic size and automatically flow and size to fit the containing HTML element or browser window size by removing the Width and Height attributes completely (I talk about this at the end of my layout tutorial here).  If we want to set a design-time width and height on our application, we can do that by setting a d:DesignWidth="640" and d:DesignHeight="476" attribute on the root UserControl element.  This will cause the designer to default to that size dimension when using the designer on the application.

    Building our Chat Application: Adding Controls and Colors

    Now that we have the core layout of our chat application defined, let's add some controls to it and start to customize how it looks.

    We'll start by selecting the root Grid layout panel and customize its background color to be a blue gradient.  One easy approach we can use to select a particular control is to use the "Interaction" panel and then click the control we want to select within it:

    We can then use the "Brushes" property panel to customize a blue LinearGradient brush for the background of our Grid:

    Once we have this set we'll work on the bottom of our chat window, and add a "Send" button to it:

    For our chat message textbox we'll use a standard textbox.  But to add a little more pizzazz we'll first add a border control with a "RoundRadius" of 5 and a Background and BorderBrush like so:

    We'll then embed our TextBox within the Border control. 

    Important Tip: To nest the TextBox within the Border control using the design-surface, we'll want to double-click the Border control within the interaction window.  This will set it as the active insertion control in the design surface, and highlight it in yellow like below:

    We can then use the control toolbox to select a TextBox control and add it into the Border control.  We'll set the TextBox's background and border brush to pick up the nice curved look from the parent Border control:

     

    The XAML markup generated by Blend will look like below (notice how the TextBox is nested under the Border control - it wouldn't have been if the Border hadn't been the active insertion control):

    We can repeat the above process for the header row as well, and embed a TextBlock within a Border control and add a image control to the right column to create UI like so:

     

    The XAML markup generated by Blend looks like below:

    Last but by no means least, we'll add another Border control in our center row and add a ListBox control inside it.  We'll configure the Border control to stretch across both columns in our Grid, and customize its background and foreground colors.  We'll then put some test message inside the ListBox as placeholder text (we'll customize the UI and databind real values later):

    The XAML markup generated by Blend looks like below:

     

    And now when we run the application we have a basic chat IM client (with hard coded values) running in the browser.  As we resize the browser the application will automatically flow and resize to fit the window.

    We still have a bunch of UI work to-do to make our IM client look less lame, but at least we now have something up and running.

    Building our Chat Application: Adding "ChatMessage" and "ChatSession" classes

    Now that we have created our initial UI within Expression Blend, let's open up the same project in Visual Studio and add some chat classes that we can use to bind our UI against.

    We can open up the project in Visual Studio either by selecting File->Open Project inside VS 2008 and selecting the project file for our project, or within Expression Blend we can right-click on the project node and choose the "Edit in Visual Studio" menu item to launch VS 2008 with the project open:

    VS 2008's Silverlight support in Beta1 has project management support for Silverlight 2 solutions, full intellisense and event-wireup support, and support for debugging Silverlight applications running both on Windows and the Mac.  VS 2008 also has split-view editing support for Silverlight .xaml files.  For example, here it the same Page.xaml file we built above in Blend open inside VS 2008:

    The VS 2008 design-view in Beta1 isn't interactive (meaning it is still read-only).  Changes you make in source-view, though, are updated immediately in design-view - which gives you a nice XAML-pad experience (and VS 2008 supports full XAML source intellisense with Silverlight 2 Beta1).

    For this blog post we aren't going to be using the Visual Studio XAML editor.  Instead we are going to create some classes that we'll use to represent a ChatSession and associated chat messages.  We'll then use Expression Blend to bind our UI controls against these.

    We'll start by adding a new class called "ChatMessage" that defines two public properties:

    We'll then create a class called "ChatSession" that represents a chat session.

    The ChatSession class above has three public properties.  The first two properties represent the remote user name and avatar on the other end of the chat. 

    The third property is a collection of the past chat messages.  Notice that its type is not a List collection - but rather an ObservableCollection collection.  ObservableCollection might not be a familiar class to you if you are coming from an ASP.NET background - but those coming from a Windows Forms or WPF background are probably familiar with it.  Basically it is a generic collection class that raises change notification events when items are added/removed from it (or when items that implement INotifyPropertyChanged within it have their properties changed).  This comes in very handy when doing data-binding - since UI controls can use these notifications to know to automatically refresh their values without a developer having to write any code to explicitly do so.

    The ChatSession class then has two public methods - one whose job it is to connect to a chat server, and another whose job it is to send messages to the chat server.  For the sake of simplicity (and because I don't have a chat server) I've just faked out these methods.  In real-life we would probably use the network sockets implementation built-into Silverlight to connect to a remote chat server.

    The ChatSession class implements the INotifyPropertyChanged interface - which means it exposes a public "PropertyChanged" event.  We'll raise this event within our class when we change the properties on it.  This will enable listeners (for example: controls data-binding against it) to be notified when changes in the property values occur - which allows them them to rebind the values.

    Implementing Fake Data for Design-time Databinding

    From a purely functional perspective, the above code is all we need in order to implement our chat client.  To help improve the design-time experience in Blend, though, we'll also add a constructor that checks whether we are in runtime or design-time mode, and loads up our ChatSession object with "fake data" if it is being hosted in a designer:

    We'll see in a moment how this helps make it easier to visualize data-bound data in the designer.

    Building our Chat Application: Wiring up UI using DataBinding in Expression Blend

    Now that we have the ChatMessage and ChatSession objects defined, we can use them within Expression Blend to databind our UI controls. 

    I introduced how data-binding in Silverlight and WPF work in my Tutorial 5: Using Databinding and the ListBox control to display list data post from last week.  In today's post we'll be using Expression Blend to wire-up the databinding expressions instead of manually typing them.  We'll start by using the "Data" panel under the "Project" panel inside Blend:

    We'll click the "+ CLR Object" link in the "Data" panel to pull up a dialog that allows us to pick any .NET object to databind our UI controls against.  We'll use it to select the "ChatSession" object we just created:

    This will cause the ChatSession object to be added to our Data tray, and expose its properties (and sub-properties) in a tree-view:

    We can then bind any of our UI controls in the design-view to these properties by selecting them in the "Data" tray and dragging/dropping them onto the UI controls in the design-surface.  For example, we could replace the static "ScottGu" label with a {Binding RemoteUserName} databinding expression by dragging the RemoteUserName property from the Data tray on top of it:

    When we drop the "RemoteUserName" property onto the TextBlock, Blend will prompt us like above to either Bind the property to the existing TextBlock, or create a new Control to represent the property.  If we choose the default (bind to the existing control), Blend will then ask us what type of binding expression we want:

    We'll indicate we want a "OneWay" binding to the TextBlock's "Text" property.  When we click ok our control will be updated with a {Binding RemoteUserName} expression for its "Text" property. 

    We can repeat this drag/drop interaction for the Image control (with the RemoteAvatarUrl property) as well as the ListBox (with the MessageHistory collection property).  When we are done Blend will show our "dummy" data within the design-view surface like so:

    You might be wondering about the contents of the ListBox - why do the items show up as "ChatClient.ChatMessage"?  Well, right now the ListBox is binding to a collection of custom .NET objects and the "ChatClient.ChatMessage" string is the value being returned by calling "ToString()" on the ChatMessage instances.

    We can modify this to look better by adding a to the ListBox like so:

    Note: For the Blend 2.5 March preview release of Blend you have to define datatemplates in source-view.  In future preview releases you'll be able to use the designer to define them as well.  This feature is already available for WPF projects if you want to play with it: As a designer, you can interactively create the look of data with a full WYSIWYG experience. Just create a WPF project to try it out.  

    Doing this will then cause our UI to look like below at design-time: