扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
作者:中国IT实验室 来源:中国IT实验室 2007年10月1日
关键字:
在本页阅读全文(共2页)
实现业务实体
业务实体具有以下特点:
如本文前面所述,在您的应用程序中表示业务实体的方法有很多(从以数据为中心的模型到更加面向对象的表示法):
以下各节将介绍如何使用这些格式来表示业务实体。为帮助您确定特定环境中最适宜的业务实体表示,以下各节将介绍如何为各业务实体格式执行以下任务:
以下各节还针对非功能性要求(包括性能、效率、可缩放性和可扩展性)考虑了每种业务实体表示的适用性。
将业务实体表示为 XML以下示例显示了如何将一个简单的业务实体表示为 XML。该业务实体包含一个产品。
<?xml version="1.0"?> <Product xmlns="urn:aUniqueNamespace"> <ProductID>1</ProductID> <ProductName>Chai</ProductName> <QuantityPerUnit>10 boxes x 20 bags</QuantityPerUnit> <UnitPrice>18.00</UnitPrice> <UnitsInStock>39</UnitsInStock> <UnitsOnOrder>0</UnitsOnOrder> <ReorderLevel>10</ReorderLevel> </Product> |
当使用 XML 表示业务实体数据时,请考虑以下原则:
将业务实体表示为 XML 的优点如下:
将业务实体表示为 XML 的缺点如下:
通用 DataSet 是 DataSet 类的实例,它是在 ADO.NET 的 System.Data 命名空间中定义的。DataSet 对象包含一个或多个 DataTable 对象,用以表示数据访问逻辑组件从数据库检索到的信息。
图 7 所示为用于 Product 业务实体的通用 DataSet 对象。该 DataSet 对象具有一个 DataTable,用于保存产品信息。该 DataTable 具有一个 UniqueConstraint 对象,用于将 ProductID 列标记为主键。DataTable 和 UniqueConstraint 对象是在数据访问逻辑组件中创建该 DataSet 时创建的。
图 7:用于 Product 业务实体的通用 DataSet
图 8 所示为用于 Order 业务实体的通用 DataSet 对象。此 DataSet 对象具有两个 DataTable 对象,分别保存订单信息和订单详细信息。每个 DataTable 具有一个对应的 UniqueConstraint 对象,用于标识表中的主键。此外,该 DataSet 还有一个 Relation 对象,用于将订单详细信息与订单相关联。
图 8:用于 Order 业务实体的通用 DataSet
以下代码显示了如何从数据访问逻辑组件检索通用 DataSet ,然后将该 DataSet 绑定到 DataGrid 控件,再将该 DataSet 传递到数据访问逻辑组件以保存对数据所做的更改:
// 创建 ProductDALC 对象 ProductDALC dalcProduct = new ProductDALC(); // 对 ProductDALC 调用一个方法以获取一个包含全部产品信息的 DataSet // 在客户端中使用 DataSet。 例如,把该 DataSet 绑定到用户界面控件 // 然后,把更新后的 DataSet 传递给 ProductDALC,将更改 |
您还可以在运行时查询和修改 DataSet 中的表、约束及关系。
将业务实体表示为通用 DataSet 的优点如下:
将业务实体表示为通用 DataSet 的缺点如下:
注意:这里没有这些索引生成器的编译时检查。如果指定一个无效的表名称、列名称或列类型,会在运行时捕获该错误。使用通用 DataSet 时不支持 IntelliSense。
有类型的 DataSet 是包含具有严格类型的方法、属性和类型定义以公开 DataSet 中的数据和元数据的类。
下面列出了有类型的 DataSet 与通用 DataSet 相比的优缺点。注意,有类型的 DataSet 的实例化和封送处理性能与通用 DataSet 基本相同。
将业务实体表示为有类型的 DataSet 的优点如下:
在本示例中,dsProducts 是有类型的 DataSet 的一个实例。该 DataSet 有一个 DataTable,它由一个命名为 Products 的属性公开。该 DataTable 中的列由 ProductName 等属性公开,后者返回列的相应数据类型(而不仅仅返回对象)。
有类型的方法和属性的提供使得使用有类型的 DataSet 比使用通用 DataSet 更方便。使用有类型的 DataSet 时,IntelliSense 将可用。
将业务实体表示为有类型的 DataSet 的缺点如下:
定义自定义业务实体组件
表示业务实体的自定义类通常包含以下成员:
图 9 所示为使用自定义实体类的方法。注意,实体类并不知道数据访问逻辑组件或基础数据库;所有数据库访问都由数据访问逻辑组件执行,以集中数据访问策略和业务逻辑。此外,在层间传递业务实体数据的方式与表示业务实体的格式也没有直接关系;例如,可以在本地将业务实体表示为对象,而用另一种方法(如标量值或 XML)将业务实体数据传递到其他层。
定义自定义业务实体组件的建议
在实现自定义实体组件时,请考虑以下建议:
您可以对业务实体执行 XML 序列化而无需在实体中实现任何附加代码。然而,只有对象中的公共字段和公共读/写属性被序列化为 XML。专用字段、索引生成器、专用属性、只读属性及对象图不会被序列化。您可以使用自定义实体中的属性控制结果 XML。
格式类将序列化对象的所有公共和专用字段及属性。BinaryFormatter 将对象序列化为二进制格式,SoapFormatter 将对象序列化为 SOAP 格式。使用 BinaryFormatter 的序列化比使用 SoapFormatter 的序列化速度要快。要使用任何一个格式类,都必须将实体类标记为 [Serializable] 属性。如果需要显式控制序列化格式,您的类还必须实现 ISerializable 接口。
注意:还原序列化某个对象时,不会调用默认的构造函数。对还原序列化添加这项约束,是出于性能方面的考虑。
定义自定义实体的优点如下:
// 使用该 ProductDALC 对象创建和填充一个 ProductEntity 对象。
// 此代码假设 ProductDALC 类有一个名为 GetProduct 的方法,
// 该方法使用 Product ID 作参数(本例中为 21),并返回一个
// 包含该产品的所有数据的 ProductEntity 对象。
ProductEntity aProduct = dalcProduct.GetProduct(21);
// 更改该产品的产品名称
aProduct.ProductName = "Roasted Coffee Beans";
在上述示例中,产品是一个名为 ProductEntity 的自定义实体类的一个实例。ProductDALC 类有一个名为 GetProduct 的方法,后者创建一个 ProductEntity 对象,将某个特定产品的数据填充到该对象,然后返回 ProductEntity 对象。调用应用程序可以使用 ProductName 等属性访问 ProductEntity 对象中的数据,并且可以调用方法以操作该对象。
在上述示例中,调用应用程序对 ProductEntity 对象调用一个名为 IncreaseUnitPriceBy 的方法。在调用应用程序对 ProductDALC 对象调用相应方法,从而将 ProductEntity 对象保存到数据库之前,这一更改并不是永久性的。
定义自定义实体的缺点如下:
定义带有 CRUD 行为的自定义业务实体组件
在定义一个自定义实体时,可以提供方法以完全封装对基础数据访问逻辑组件的 CRUD 操作。这是比较传统的面向对象的方法,可能适用于复杂的对象域。客户端应用程序不再直接访问数据访问逻辑组件类,而是创建一个实体组件并对该实体组件调用 CRUD 方法。这些方法将调用基础的数据访问逻辑组件。
图 10 所示为带有 CRUD 行为的自定义实体类的作用。
定义带有 CRUD 行为的自定义实体类的优点如下:
定义带有 CRUD 行为的自定义实体类的缺点如下:
表示数据和在层间传递数据的建议
在您的应用程序中表示数据的方式以及在层间传递数据的方式不一定要相同。然而,一套一致而有限的格式能够降低对附加转换层的需要,从而提高性能并方便维护。
应根据自己特定的应用程序要求和操作数据的方式选择数据格式。这里并没有一个通用的表示方式,特别是由于当今的许多应用程序都需要支持多个调用程序。然而,我们还是建议遵循以下一般原则:
事务处理
当今的大多数应用程序都需要支持事务处理以保持系统数据的完整性。事务处理的管理方法有多种,但每种方法都可归于以下两种基本编程模型之一:
本节提供一些指导原则和建议,帮助您在数据访问逻辑组件和业务实体组件中实现事务处理支持。
实现事务处理
在大多数环境中,事务处理的根本是业务过程而不是数据访问逻辑组件或业务实体组件。这是因为业务过程一般要求事务处理跨多个业务实体而不仅仅是单个业务实体。
然而,也可能出现在没有高层次业务过程的帮助下对单个业务实体执行事务性操作的情况。例如,要把一个新客户添加到前面讨论的数据库中,您必须执行以下操作:
只有这两个操作都成功后客户才会被添加到数据库中。如果 Customer 业务实体不会成为启动该事务处理的更大的业务过程的一部分,则应在 Customer 业务实体中使用手动事务处理。手动事务处理不要求与 Microsoft 分布式事务处理协调器 (DTC) 之间进行任何进程间通信,因此比自动事务处理要快得多。
图 11 所示为确定使用手动事务处理还是自动事务处理的方法。由于 COM+ 事务处理的系统开销,建议将事务处理放到数据库中并在存储过程中控制事务性行为(如果可能)。
图 11:确定如何实现事务处理
注意:如果从基于 ASP.net 的客户端进行调用,并且没有用于启动事务处理的业务过程,则您可能会从 ASP.NET 代码中启动该事务处理。这种设计并不好;您决不能从基于 ASP.NET 的客户端启动事务处理,而应将数据的展示与业务过程相分离。此外,由于网络滞后等问题还会导致性能问题,因为这是要实际部署在其他层上的最常见的层。
在数据访问逻辑组件中使用手动事务处理的建议
在数据访问逻辑组件中实现手动事务处理时,请考虑以下建议:
在数据访问逻辑组件中使用自动事务处理的建议
虽然 COM+ 事务处理会带来一些系统开销,但自动事务处理能够提供比手动事务处理更简单的编程模式,而且在事务处理跨多个分布式数据源(与 DTC 一起工作)时必须使用自动事务处理。在数据访问逻辑组件中实现自动事务处理时,请考虑以下建议:
以下代码示例显示了如何在数据访问逻辑组件类中支持自动事务处理:
using System.EnterpriseServices;
[Transaction(TransactionOption.Supported)] |
如果使用自动事务处理,则数据访问逻辑组件应在事务处理中表明操作是否成功。如果要隐式表明,应使用 AutoComplete 属性注释您的方法并在操作失败时发出一个异常。如果要显式表明,应对 ContextUtil 类调用 SetComplete 或 SetAbort 方法。
在业务实体组件中使用自动事务处理
在实现带有行为的自定义业务实体组件时,可以使用自动事务处理来指定这些对象的事务性行为。有关使用自动事务处理指定业务实体组件事务性行为的建议与前述有关在数据访问逻辑组件中实现自动事务处理的建议相同。
注意:如果业务实体组件不包含任何要求其在事务处理中表明是否成功的业务逻辑,则它可以忽略事务处理环境。自定义业务实体组件不需要从 ServicedComponent 继承;事务处理环境仍将继续其流程,但实体组件将忽略事务处理环境。
验证
您可以在应用程序的许多层上进行数据验证。各层适用不同的验证类型:
常用验证有两种:
有时,您可能希望实现额外的聚合过程或转换过程。这种方法在验证和转换经常变化时可能很有用,但会损失性能。例如,如果一个 ISV 想要使用相同的组件支持数据库架构的两个版本,则您可以创建一个单独的组件来执行两个数据库架构版本之间的验证和转换。
如何使用 XSD 架构验证 XML
要使用 XSD 架构验证 XML 文档,请执行以下步骤:
以下代码显示了 ValidationType 枚举的使用:
vr.ValidationType = ValidationType.Schema; ' 指定 XSD 架构验证
public void MyHandlerMethod(object sender, ValidationEventArgs e) { Console.WriteLine("验证错误:" + e.Message); } |
try { while (vr.Read()) { // 适当处理 XML 数据... } } catch (XmlException ex) { Console.WriteLine("XmlException: " + ex.Message); } vr.Close(); |
如何在业务实体组件的属性存取器中验证数据
以下代码片段显示了如何在自定义实体的属性存取器中进行简单验证。如果验证测试失败,您可以发出一个异常以显示问题的性质。也可以在属性存取器集合中使用正则表达式来验证特定的数据和格式。
public class ProductDALC { ... public short ReorderLevel { get { return reorderLevel; } } set { if (value < 0) { throw new ArgumentOutOfRangeException("ReorderLevel 不能为负数。"); } reorderLevel = value; } // 加上 ProductDALC 类中的其他成员... |
异常管理
当 .net 应用程序出现错误时,通常的建议是发出异常而不是从方法返回错误值。这一建议暗示了您编写数据访问逻辑组件和业务实体组件的方式。异常大体上有两种:
数据访问逻辑组件应该传播异常,并且仅在能够使客户端对异常的管理更加容易时才包装异常类型。将异常包装为两种主要异常类型(技术异常和业务异常)有利于各种可能的调用程序的异常处理结构和异常发布逻辑。
您的应用程序应当发布异常信息。可以将技术异常发布到一个由系统管理员或 Windows 管理规范 (WMI) 监视工具(如 Microsoft Operations Manager)监视的日志中;将业务异常发布到一个特定的应用程序日志中。通常,应允许从数据访问逻辑组件传播异常并允许由调用程序发布异常,以便您了解异常的整个环境。
以下示例说明了这些建议:
public class CustomerDALC { public void UpdateCustomer(Dataset aCustomer) { try { // 更新数据库中的客户... } catch (SqlException se) { // 捕获并包装异常,然后重新发出 throw new DataAccessException("数据库不可用", se); } finally { // 清除代码 } } } |
在业务实体组件中管理异常的建议
业务实体组件应当向调用程序传播异常。在业务实体组件执行验证或者当调用程序试图执行某一操作而未提供该操作所需的数据时,业务实体组件也可以产生异常。
以下示例显示了业务实体组件如何产生异常。在此示例中,如果没有提供客户的名字,Update 方法将发出一个异常:
public class CustomerEntity { public void Update() { // 检查用户已提供了所需数据。这里是客户 // 的名字 if (FirstName == "" ) { // 发出一个已定义的新的应用程序异常 throw new MyArgumentException("您必须提供名字。"); } ... } } |
授权与安全性
本节说明如何将安全性应用于数据访问逻辑组件和业务实体组件。.NET 公共语言运行库使用权限对象实现其对托管代码的强制限制机制。权限对象有三种,各自具有特定的用途:
托管代码可以使用 Principal 对象(包含对 Identity 对象的引用)来判断当事人的身份标识或角色。把 Identity 对象和 Principal 对象与用户、组帐户等大家所熟悉的概念比较可能会更容易理解。在 .NET Framework 中,Identity 对象表示用户,而角色表示成员身份和安全性环境。Principal 对象封装了 Identity 对象和角色。.NET Framework 中的应用程序根据 Principal 对象的身份标识或角色成员身份(后者更常见)授予 Principal 对象权限。
数据访问逻辑组件中的安全性建议数据访问逻辑组件的设计目的是供其他应用程序组件使用,它也是您的应用程序代码中在调用程序可以访问数据之前实现安全性的最后一个地方。
通常,数据访问逻辑组件可以依赖于由调用程序设置的安全性环境。然而,有些情况下数据访问逻辑组件必须执行自己的授权检查,以确定是否允许当事人执行所请求的操作。授权在身份验证后进行,并使用当事人身份标识与角色等有关信息来确定该当事人可以访问的资源。
在以下情况下,应在数据访问逻辑组件层次上执行授权检查:
在定义了 Identity 对象和 Principal 对象后,可以用三种方式执行基于角色的安全性检查:
以下代码示例显示了如何使用 PrincipalPermissionAttribute 为数据访问逻辑组件类中的方法指定基于角色的声明性安全性检查:
using System; using System.Security.Permissions; public class CustomerDALC public CustomerDALC() // 使用 PrincipalPermissionAttribute 要求此方法的调用程序 |
以下代码显示了如何创建具有所需身份标识和角色的 Principal 对象,以便对 CustomerDALC 对象调用 DeleteCustomer 方法:
using System; public class MainClass Console.Write("密码:"); if (Password == "password" && UserName == "MyUser") // 创建角色 // 创建一个通用当事人 // 创建一个 CustomerDALC 对象,并尝试调用它的 DeleteCustomer 方法。 |
理想情况下,在连接到数据库时应使用 Windows 身份验证而不是 SQL Server 身份验证。然而,应使用服务帐户并避免模拟连接到数据库,因为它会妨碍连接池。连接池需要相同的连接字符串;如果尝试使用不同的连接字符串打开数据库,就会创建单独的连接池,而这将限制可缩放性。
安全通信建议要实现调用应用程序与数据访问逻辑组件之间的安全通信,请考虑以下建议:
业务实体组件中的安全性建议
如果将业务实体实现为数据结构(如 XML 或 DataSet),则不需要实现安全性检查。然而,如果将业务实体实现为带有 CRUD 操作的自定义业务实体组件,请考虑以下建议:
部署
本节提供一些建议以帮助您确定如何部署数据访问逻辑组件和业务实体组件。
部署数据访问逻辑组件
部署数据访问逻辑组件的方法有两种:
部署业务实体
应用程序的许多不同层都要使用业务实体。根据业务实体的实现方式,如果您的应用程序跨越各个物理层,则需要将业务实体部署到多个位置。下面列出了在不同实现方案中部署业务实体的方法:
如何定义数据访问逻辑组件类
以下代码示例定义一个名为 CustomerDALC 的类,它是用于 Customer 业务实体的数据访问逻辑组件类。CustomerDALC 类为 Customer 业务实体实现 CRUD 操作,并提供了其他方法为此对象封装业务逻辑。
public class CustomerDALC { private string conn_string; public CustomerDALC() public CustomerDataSet GetCustomer(string id) public string CreateCustomer(string name, public void UpdateCustomer(CustomerDataSet updatedCustomer) public void DeleteCustomer(string id) public DataSet GetCustomersWhoPurchasedProduct(int productID) |
如何使用 XML 表示数据的集合和层次结构
以下示例显示了如何在 XML 文档中表示数据的集合和层次结构。该 XML 文档表示客户的一个订单;注意,元素 <OrderDetails> 包含一个该订单的详细信息集合。
<Order xmlns="urn:aUniqueNamespace"> <OrderID>10248</OrderID> <CustomerID>VINET</CustomerID> <OrderDate>1996-07-04</OrderDate> <ShippedDate>1996-07-16</ShippedDate> <OrderDetails> <OrderDetail> <ProductID>11</ProductID> <UnitPrice>14.00</UnitPrice> <Quantity>12</Quantity> </OrderDetail> <OrderDetail> <ProductID>42</ProductID> <UnitPrice>9.80</UnitPrice> <Quantity>10</Quantity> </OrderDetail> <OrderDetail> <ProductID>72</ProductID> <UnitPrice>34.80</UnitPrice> <Quantity>5</Quantity> </OrderDetail> </OrderDetails> </Order> |
如何在 .net 应用程序中编程应用样式表
要在 .NET 应用程序中编程应用样式表,请执行以下步骤:
如何创建有类型的 DataSet
可以使用有类型的 DataSet 表示业务实体。创建有类型的 DataSet 的方法有多种:
注意:也可以编程定义有类型的 DataSet,即从 DataSet 继承并定义方法、属性和嵌套类以表示该 DataSet 的结构。最简单的方法是使用以下过程之一创建一个有类型的 DataSet,然后将此有类型的 DataSet 类用作将来您自己的有类型的 DataSet 类的基础。
使用数据适配器创建有类型的 DataSet
要使用数据适配器创建有类型的 DataSet,请执行以下步骤:
从 XSD 架构文件创建有类型的 DataSet
要使用 Visual Studio .NET 从 XSD 架构文件创建有类型的 DataSet,请执行以下步骤:
使用 XSD 架构定义工具 (xsd.exe) 创建有类型的 DataSet
XML 架构定义工具可以从 XSD 架构文件、XDR 架构文件或 XML 实例文档生成有类型的 DataSet。以下命令使用名为 XsdSchemaFile.xsd 的 XSD 架构文件,在当前目录中名为 XsdSchemaFile.cs 的 Visual C# 源文件中生成一个有类型的 DataSet:
xsd /dataset /language:C# XsdSchemaFile.xsd
如何定义业务实体组件
以下示例显示了如何为 Product 业务实体定义自定义实体类:
public class ProductEntity // 公共属性,用于公开 Product 实体的状态 // 执行本地化处理的方法和属性 |
如何表示业务实体组件中数据的集合和层次结构
以下示例显示了如何为 Order 业务实体定义自定义实体类。每个订单都包含许多订购项目,这些订购项目保存在 OrderEntity 类的一个 DataSet 中。
public class OrderEntity // 专用字段,用于保存订单详细信息 // 公共属性,用于提供订单信息 // 公共属性,用于提供订单详细信息 // 附加方法,用于简化对订单详细信息的访问 // 附加属性,用于简化对订单详细信息的访问 |
关于 OrderEntity 类,请注意以下几点:
如何将业务实体组件绑定到用户界面控件
可以将用户界面控件绑定到 Windows 窗体和 ASP.NET 应用程序中的自定义实体。有两种可能的方案:
OrderDALC dalcOrder = new OrderDALC();
// 使用 dalcOrder 为订单 ID 10248 获取一个 OrderEntity 对象。 // 将 OrderEntity 的 OrderID 属性绑定到 TextBox 控件。 // 将 OrderEntity 的 CustomerID 属性绑定到另一个 TextBox 控件。 // 将 OrderEntity 的 OrderDate 属性绑定到 DatePicker 控件。 // 将 OrderEntity 的 ShippedDate 属性绑定到另一个 DatePicker 控件。 // 将 OrderEntity 的 OrderDetails DataSet 绑定到 DataGrid 控件。 |
准备好后,您可以将修改后的 OrderEntity 对象传递给 OrderDALC,以便将数据保存到数据库中,如以下代码所示。
// 通过 dalcOrder 将 OrderEntity 对象保存到数据库中。
// 此代码假设 OrderDALC 类有一个名为 UpdateOrder() 的方法,
// 该方法接收一个 OrderEntity 参数,并更新数据库中的相应项
dalcOrder.UpdateOrder(order);
// 使用 dalcOrder 获取客户“VINET”的 OrderEntity 对象数组。
// 此代码假设 OrderDALC 类有一个名为
GetOrdersForCustomer(),
// 的方法,该方法返回特定客户的 OrderEntity 对象数组。
OrderEntity[] orderEntities = dalcOrder.GetOrdersForCustomer("VINET");
// 将该数组绑定到 DataGrid 控件。
dataGrid1.DataSource = orderEntities;
准备好后,您可以将修改后的数组传递给 OrderDALC,以便将数据保存到数据库中,如以下代码所示:
// 通过 dalcOrder 将 OrderEntity 对象保存到数据库中。
// 此代码假设 OrderDALC 类有一个名为 UpdateOrder() 的方法,该方法获取
// 一个 OrderEntity 对象数组,并更新数据库中的相应项。
dalcOrder.UpdateOrders(orderEntities);
如何在业务实体组件中提供事件
自定义实体可以在业务实体状态修改时产生事件。这些事件可用于获得丰富的客户端用户界面设计,因为这使得无论数据显示在哪里都可以对其进行刷新。以下代码示例显示了如何在 OrderEntity 类中产生业务实体相关事件:
// 为所有业务实体事件定义公用事件类 // 定义一个代理,用于为业务实体相关事件指定签名 // 定义自定义实体类,它可以在业务实体状态改变时产生事件 // 专用字段,用于保存业务实体的状态 // 公共属性,用于提供业务实体的状态 // 必要时使用更多成员... |
关于上述代码,请注意以下几点:
EntityEvent 类提供有关业务实体相关事件的信息。EntityEventHandler 代理为自定义实体类产生的所有业务实体相关事件指定签名。该代理签名遵循所建议的 .NET Framework 事件处理程序代理的原则。
OrderEntity 类定义了两个名为 BeforeChange 和 AfterChange 的事件。
OrderEntity 中的属性设置器在业务实体状态改变前产生一个 BeforeChange 事件,在业务实体状态改变后产生一个 AfterChange 事件。
如何将业务实体组件序列化为 XML 格式
本节讨论以下问题:
使用 XmlSerializer 序列化自定义实体对象
XML Web Services 中对象的 XML 序列化
序列化自定义实体对象的默认 XML 格式
控制序列化自定义实体对象的 XML 格式
使用 XmlSerializer 序列化自定义实体对象
以下代码示例显示了如何使用 XmlSerializer 类将 OrderEntity 对象序列化为 XML 格式:
using System.Xml.Serialization; // 此命名空间包含 XmlSerializer 类 // 将 OrderEntity 对象序列化为名为“MyXmlOrderEntity.xml”的 XML 文件 |
在 XML Web services 中序列化对象
以下代码示例显示了如何编写使用自定义实体对象的 XML Web services:
namespace MyWebService // 使用 dalcOrder 获取指定订单 ID 的 OrderEntity 对象。 // 返回 OrderEntity 对象, 该对象将自动序列化。 [WebMethod] // 使用 dalcOrder 将 OrderEntity 对象的数据保存到数据库中。 |
关于上述代码,请注意以下几点:
GetOrder 方法接收一个订单 ID 作为参数,并返回包含该订单的数据的 OrderEntity 对象。
UpdateOrder 方法接收一个 OrderEntity 对象并将该对象的数据保存到数据库中。
如果客户端应用程序调用 GetOrder 和 UpdateOrder 方法,OrderEntity 对象将为该方法调用自动序列化为 XML 格式。
序列化自定义实体对象的默认 XML 格式
以下 XML 文档显示了 OrderEntity 对象的默认 XML 序列化格式:
<?xml version="1.0" encoding="utf-8"?> <OrderEntity xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <OrderID>10248</OrderID> <CustomerID>VINET</CustomerID> <OrderDate>1996-07-04T00:00:00.0000000+01:00</OrderDate> <OrderDetails> ... see below ... </OrderDetails> <ShippedDate>1996-07-16T00:00:00.0000000+01:00</ShippedDate> </OrderEntity> |
上述文档说明了 XML 序列化的默认规则:
该 XML 文档的根元素与类名称 OrderEntity 相同。
OrderEntity 对象中的每个公共属性(及字段)都被序列化为具有相同名称的元素。
OrderEntity 类中的 OrderDetails 属性是一个 DataSet,DataSet 提供了内置的 XML 序列化支持。OrderDetails DataSet 的序列化结果如下:
<OrderDetails> <xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> <xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:Locale="en- UK"> <xs:complexType> <xs:choice maxOccurs="unbounded"> <xs:element name="OrderDetails"> <xs:complexType> <xs:sequence> <xs:element name="OrderID" type="xs:int" minOccurs="0" /> <xs:element name="ProductID" type="xs:int" minOccurs="0" /> <xs:element name="UnitPrice" type="xs:decimal" minOccurs="0" /> <xs:element name="Quantity" type="xs:short" minOccurs="0" /> </xs:sequence> </xs:complexType> </xs:element> </xs:choice> </xs:complexType> </xs:element> </xs:schema> <diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1"> <NewDataSet> <OrderDetails diffgr:id="OrderDetails1" msdata:rowOrder="0" diffgr:hasChanges="inserted"> <OrderID>10248</OrderID> <ProductID>11</ProductID> <UnitPrice>14</UnitPrice> <Quantity>12</Quantity> </OrderDetails> <OrderDetails diffgr:id="OrderDetails2" msdata:rowOrder="1" diffgr:hasChanges="inserted"> <OrderID>10248</OrderID> <ProductID>42</ProductID> <UnitPrice>9.8</UnitPrice> <Quantity>10</Quantity> </OrderDetails> <OrderDetails diffgr:id="OrderDetails3" msdata:rowOrder="2" diffgr:hasChanges="inserted"> <OrderID>10248</OrderID> <ProductID>72</ProductID> <UnitPrice>34.8</UnitPrice> <Quantity>5</Quantity> </OrderDetails> </NewDataSet> </diffgr:diffgram> </OrderDetails> |
关于 DataSet 的序列化,请注意以下几点:
<xs:schema> 段描述了 DataSet 的结构,包括表、列名称和列类型。
<xs:diffgram> 段包含该 DataSet 的数据。每个 <OrderDetails> 元素表示该 DataSet 中 OrderDetails 表中的单独一行。
控制序列化自定义实体对象的 XML 格式
您可以在自定义实体类中使用 .NET 属性来控制属性和字段序列化为 XML 的方式。请考虑以下修订后的 OrderEntity 类:
[XmlRoot(ElementName="Order", Namespace="urn:MyNamespace")] [XmlAttribute(AttributeName="CustID")] [XmlElement(ElementName="Ordered")] public DataSet OrderDetails {...获取和设置代码,同前...} [XmlElement(ElementName="Shipped") // 必要时使用更多成员... |
将 OrderEntity 对象序列化为 XML 后,其格式如下:
<?xml version="1.0" encoding="utf-8" ?> <Order ID="10248" CustID="VINET" xmlns="urn:MyNamespace" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <Ordered>1996-07-04T00:00:00.0000000+01:00</Ordered> <OrderDetails>...详细代码同前...</OrderDetails> <Shipped>1996-07-16T00:00:00.0000000+01:00</Shipped> </Order> |
如何将业务实体组件序列化为 SOAP 格式
以下代码示例显示了如何使用 SoapFormatter 类将 OrderEntity 对象序列化为 SOAP 格式。当使用 SOAP 协议向或从 XML Web services 传递对象,或者当使用 HTTP 远程通道向或从 Remoting 服务器传递对象时,也会发生 SOAP 序列化(隐式)。此外,您也可以在使用 TCP 远程通道时指定 SOAP 格式化。
using System.Runtime.Serialization.Formatters.Soap; // 用于 SoapFormatter 类 // 将 OrderEntity 对象序列化为名为“MySoapOrderEntity.xml”的 SOAP (XML) 文件 |
要对自定义实体组件使用 SOAP 序列化,必须使用 Serializable 属性注释您的实体类,如以下代码所示:
[Serializable] public class OrderEntity { // 成员,同前 |
如果要自定义序列化过程中生成的 SOAP 格式,实体类必须实现 ISerializable 接口。您必须提供一个 GetObjectData 方法供 SoapFormatter 在序列化过程中调用,并提供一个特殊构造函数供 SoapFormatter 在还原序列化过程中调用以重新创建对象。以下代码显示了 ISerializable 接口、GetObjectData 方法和特殊构造函数的使用:
using System.Runtime.Serialization; // 用于 ISerializable 接口以及相关类型 // 还原序列化构造函数,由 SoapFormatter 在还原序列化过程中调用 |
如何将业务实体组件序列化为二进制格式
以下代码示例显示了如何使用 BinaryFormatter 类将 OrderEntity 对象序列化为二进制格式。当使用 TCP 远程通道向或从 Remoting 服务器传递对象时,也会发生二进制序列化(隐式)。此外,为提高性能,您也可以在使用 HTTP 远程通道时指定二进制格式化。
using System.Runtime.Serialization.Formatters.Binary; // 用于 BinaryFormatter 类 // 将 OrderEntity 对象序列化为名为“MyBinaryOrderEntity.dat”的二进制文件 |
要对自定义实体对象使用二进制序列化,必须使用 Serializable 属性注释您的自定义实体类。要自定义序列化过程中生成的二进制格式,自定义实体类必须实现 ISerializable 接口。这两种方案中的详细代码与 SOAP 序列化的代码相同。
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。