DevExpress Persistent Object v.1.5学习笔记(一)

DevExpress Persistent Object v.1.5学习笔记(一)

原创:bnPYSse

著名的Delphi第三方控件开发商DevExpress公司新近公布了其在.NET的新型数据应用工具eXpress Persistent Object v.1.5 for .Net,其发行版本的代号为XPO,是一款专门用于.NET环境下的数据库应用开发工具。DevExpress的开发能力已为广大程序员所熟知,正是基于对该公司开发工具的信任,我想此款控件个头虽然不是很大,但其开发能力应该是有所保证的。在其应用过程当中,有一些心得,不敢独享,现整理成文,供大家参考学习。由于水平有限,错误之处再所难免,欢迎批评指正并交流。可与我Email联系。

eXpress Persistent Objects for .NET为软件的对象与关系数据库之间提供了一个强大的桥梁作用,可以为开发者提供相当大的自由度来创建真实的商业对象,而不必去考虑处理如何将其映射到数据表中那些繁复的细节处理。eXpress Persistent Objects for .NET完整地从开发者角度抽象了数据库层,让开发人员可以完全沉浸在面向对象的设计氛围里。通过XPO,开发人员建立的应用程序可以很好地工作在各个不同的数据库系统之下(不久即将支持MSAccess和MSSQL数据库系统,难道现在不支持么?呵呵),而不用更改一点儿代码。

XPO非常容易上手。如果您看过Microsoft.Visual.Studio.NET.2003所带的例子Duwamish7,在其中的Common模块当中,一定会被其数据表映射的代码段看个头晕脑胀,而且觉得微软的程序员难道会这么机械么?而从其代码来看,却又不得不承认,那帮子程序员的确是够机械的。然而如果有了XPO,你将完全可以从那样机械的代码当中解放出来。

开发人员所需要做的仅仅是定义一个持久性的对象类,XPO.NET会自动为其生成数据库。XPO.NET会透明(在DevExpress公司的介绍当中,Transparently这个词频繁地出现,也许正是其强调的一个亮点之处吧)的处理类与对象实例之间的关系,不必为灵活性而牺牲其易用性。如果想更多地控制O/R映射关系,可以使用XPO内建的属性提供的附加映射信息来满足任何商业需求。

利用XPO.NET可以从对象模型直接进行数据库应用程序的开发,不必在表、列、关系及约束等方面花费更多的时间,而把主要的精力放在代码的编写上,它使您把主要的精力集中在应用需求等问题上,再也不必要为数据库的瓶颈等问题而头疼了。总之,是好处大大、功能强强的,套用一句DevExpress公司的宣传口号是:

Total Control, Flexibility and Power Bridging the Gap Between the Object World and Relational Databases. 

 
XPO示例图
1、eXpress.Persistent.Object.v.1.5的新特性
  • 映射已存在的数据库。XPBaseObject做为基类可为持久性对象提供服务。
  • 支持MSSQL7.0(^_^,这也算一个新特性?呵呵)。
  • 页面级收集器。PageSelector类允许对一个源容器进行页面管理。
  • 设计期的页面管理。XPPageSelector组件允许在设计时段指定一个页面容器做为数据源,并绑定到用户界面。
  • 容器内容过滤。XPCollection.Filter属性允许过滤出已存在的容器内容,并可获取匹配过滤标准的子容器项目。
  • 容器内容排序和过滤。非持久性属性可用于过滤和排序XPCollection容器的内容。
  • 排序与过滤选项。XPCollection.CaseSensitive属性可控制容器成员的大小写。
  • 新的标准运算。AggregateOperand允许通过Aggregate.Sum,Aggregate.Count,Aggregate.Min和Aggregate.Max操作选项进行运算。
  • 支持值对象
  • 值与类型转换。借助于ValueConverter和ValueConverterAttribute类可以实现数据库值与持久性属性之间的双向转换。
  • 数据库视图的映射。持久性对象现可以映射到数据库视图。
  • 持久性空值。空值可通过NullValueAttribute被存储在数据库中。
  • 自定义数据库类型。利用持久性属性或字段映射,利用DbTypeAttribute可明确标识出列的类型。
  • 跟踪容器内容的更改。可通过CollectionChanged事件跟踪容器内容的更改。
  • 性能的提高。当对象被加载时,ExplicitLoadingAttribute要帮助优化数据库查询性能。
  • XPBaseObject。XPBaseObject现可支持IEditableObject。可通过此接口控制对象的改变。
  • XPBaseObject。XPBaseObject现拥有一个虚拟的AfterConstruction方法允许实现逻辑创建自主对象。
  • XPCollection。XPCollection扩展CollectionChanged事件,提供在容器操作过程中执行自定义动作。
2、XPO如何工作

面向对象的应用程序设计与开发为当前的复杂应用开发提供了一个高性能与多产的手段,提高了代码重用的机会,以及当最终用户需求发生变化时更高的灵活性。

当创建一个数据库应用时,开发人员看起来总是被迫与数据表、视图、数据字段对象打交道,而不是直接处理商业对象。这种关系数据库对象领域的差距现象类似于ADO.NET和特定领域内的商业对象的差别,对开发人员来讲,同样是一极大的挑战。

Visual Studio .NET试图通过类型安全数据集来解决这个问题:一个开发人员可以拾取一个数据表并且生成一个类型安全的数据集类,使该类看上去更类似于一个事务域中的商业对象,这种机制被用于实现持久性商业对象,尽管看来此类对象更像是面向数据的一个结构。

那么有没有一种方法可以映射你设计良好的商业对象模型到关系数据库而不必处理数据表与字段呢?也许您已经猜到这个答案了。通过XPO就要以实现这样的工作。XPO从另外一个不同的角度试图来解决这个问题——通过对商业对象世界的透视。

来看一个小例子。在一个销售管理应用程序中,一个联系人的类是如下来表示的:

 
public class Contact {
      public string FirstName;
      public string LastName;
      public string PhoneNumber;
      public string Email; 
   } class Contact {
      public string FirstName;
      public string LastName;
      public string PhoneNumber;
      public string Email; 
   }

很显然,在销售管理应用系统当中所有的联系人都应该保存在数据库中,因此Contact必然是一个持久化对象。要想将其持久化,其实非常之简单,所需要做的只是将其从XPObject中进行继承:

 
using DevExpress.Xpo;
    ...
    public class Contact: XPObject {
       public string FirstName;
       public string LastName;
       public string PhoneNumber;
       public string Email;
    }
           DevExpress.Xpo;
    ...
    public class Contact: XPObject {
       public string FirstName;
       public string LastName;
       public string PhoneNumber;
       public string Email;
    }
          

一般在使用持久化对象之前,都要指定一个联接字符串连接到数据库,类似下面的代码:

 
...
    Session.DefaultSession.ConnectionString="...";
    Contact contact = new Contact();
    contact.FirstName = "John";
    contact.LastName =  "Doe";
    contact.Email = "jdoe@johndoe.com";
    contact.Save();
    ...
          new Contact();
    contact.FirstName = "John";
    contact.LastName =  "Doe";
    contact.Email = "jdoe@johndoe.com";
    contact.Save();
    ...
          

通过以上如此简单的代码,就在.NET环境中创建了一个Contact表,并且插入一个记录到里面。

那么如何从数据库中取用该对象呢?XPO.NET提供了提供了XPCollection来取用对象:

 
XPCollection contacts = new XPCollection(typeof(Contact));
    foreach(Contact contact in contacts) {
      Console.WriteLine(contact.Email);
    }new XPCollection(typeof(Contact));
    foreach(Contact contact in contacts) {
      Console.WriteLine(contact.Email);
    }

比较幸运的是,XPCollection可以作为DataGrid的数据源用以在DataGrid当中显示Contect列表:

 
contactDataGrid.DataSource = contacts;
          

如果想更改显示对象在DataGrid中的显示项目,可以对Contact.DisplayableProperties进行设置:

 
contacts.DisplayableProperties = "FirstName;LastName;Email";

大多数时候,并不需要从数据库中取用全部的Contact对象,而实际情况往往是按照一定的标准查找部分对象,数据库管理系统往往提供SQL查询来完成这类任务,完全可以用来代替foreach叠代:

 
XPCollection jdoe = new XPCollection(typeof(Contact), 
	new GroupOperator(GroupOperatorType.And,
	new BinaryOperator("FirstName", "John"),
	new BinaryOperator("LastName", "Doe")));new XPCollection(typeof(Contact), 
	new GroupOperator(GroupOperatorType.And,
	new BinaryOperator("FirstName", "John"),
	new BinaryOperator("LastName", "Doe")));

以上代码即查找"John Doe"对象,类似于数据库中的SQL查询语句。

缺省情况下,容器中的对象是无序的,以下代码即取用FirstName="John"并且LastName按照升序进行排序。

 
XPCollection jdoe = new XPCollection(typeof(Contact),  
      new BinaryOperator("FirstName", "John"),
      new SortProperty("LastName", SortingDirection.Ascending);new XPCollection(typeof(Contact),  
      new BinaryOperator("FirstName", "John"),
      new SortProperty("LastName", SortingDirection.Ascending);

在绝大部分的商业模型中,数据表都不是独立存在的,表与表之间大都存在着这样那样的关系,比如,联系人往往属于某一间公司:

 
using DevExpress.Xpo;
  ...
  public class Company : XPObject {
  public string Name;
  public string PhoneNumber;
  public string WebSite;
}

public class Contact : XPObject {
  public string FirstName;
  public string LastName;
  public string PhoneNumber;
  public string Email;
  public Company Employer;
} DevExpress.Xpo;
  ...
  public class Company : XPObject {
  public string Name;
  public string PhoneNumber;
  public string WebSite;
}

public class Contact : XPObject {
  public string FirstName;
  public string LastName;
  public string PhoneNumber;
  public string Email;
  public Company Employer;
}

在数据表存在关系的情况下,XPO.NET会知道Employer属性是另外一个商业对象的引用,因而会在数据库结构中自动地维护这种关系的存在,而勿需任何手工代码来实现。

如果一个商业对象拥有子对象,比如,一个Order订单一般情况下会有若干个订单细项,这时需要给XPO.NET一个小小的“提示”,告诉它子对象将会被存储在容器当中:

 
using DevExpress.Xpo;
...
public class OrderLine : XPObject {
  public string Description;
  public double Price;
  public int Quantity;
  [Association("OrderLines")]
  public Order Order;
}

public class Order : XPObject {
  public string OrderNo;
  public string Description;

  [Aggregated]
  [Association("OrderLines")]  
  public XPCollection OrderLines {
    get { return GetCollection("OrderLines"); }
  }
} DevExpress.Xpo;
...
public class OrderLine : XPObject {
  public string Description;
  public double Price;
  public int Quantity;
  [Association("OrderLines")]
  public Order Order;
}

public class Order : XPObject {
  public string OrderNo;
  public string Description;

  [Aggregated]
  [Association("OrderLines")]  
  public XPCollection OrderLines {
    get { return GetCollection("OrderLines"); }
  }
}

对象变量允许我们在程序当中进行引用,但是在程序程序运行过程中它并非是唯一存在的,因而需要在程序运行过程当中用一个唯一指示符标识出该对象来。在每一个持久性对象当中都有一个OID属性,OID标识某个指定类的唯一标识符:

 
Contact contact = (Contact)Session.DefaultSession.GetObjectByKey(typeof(Contact), storedOID);typeof(Contact), storedOID);

通过以上的例子可以看出XPO.NET商业模型与数据表之间的透明转换,即现在开发领域讨论的比较热烈的Object-Relational Mapping,大大提高了商业的重用性和灵活性,实现了面向对象的数据库编程。在功能与Borland公司提出的ECO(Enterprise Core Object)模型非常类似,当然XPO.NET的对于数据库的连接日前只实现了SQL和Access的MDB,没办法与ECO的强大所比拟,但是使用VS.NET环境编程的朋友们,如果没办法享受C# Builder(Delphi8.NET)所提供的ECO强大魅力的情况下,使用XPO.NET是当前比较理想的选择,将编程人员的重复复杂的O\R映像关系工作中解放出来,将更我的心思应用到商业模型的实现当中。

个人认为,目前Visual.Studio.NET+Together(for .NET)+XPO.NET将是比较理想的选择。

外语水平以及理解能力有限,不当之处,请诸位多多批评指教。

posted @ 2019-08-14 08:59  grj001  阅读(123)  评论(0编辑  收藏  举报