XPO学习文档
1. 指南一
1.1 建立以及使用急速持久对象
1.1.1 对象的定义
本指南中将通过XPO来编写一个客户跟踪系统的例子。每个客户对象必须包含一个ID、name、
Company name,phone number,fax number.
要定义一个持久化对象,只要继承XPObject对象即可。基类已经拥有一个叫做“OID”的唯一标识,因而你只需定义其他的属性。如下:
[C#]
public class Customer : XPObject
{ public string Name = \"\";
public string CompanyName = \"\";
public string Phone = \"\";
public string Fax = \"\";
}
1.1.2 对象的使用
当您已经定义好了您的客户对象,您就可以在代码中使用它了。您可以象使用任何其他对象那样使用持久化对象。
[C#]
Customer myCustomer = new Customer();
myCustomer.Name = \"Mario Esprito\";
myCustomer.CompanyName = \"Infoltrix\";
myCustomer.Phone = \"(111) 345 6777\";
myCustomer.Fax = \"(222) 343 6744\";
1.1.3 对象的存储
当你已经创建了对象之后,你可以通过对象的保存方法将它保存至数据库。
[C#]
myCustomer.Save();
你也许想问…..数据库指的是什么?持久对象到底存储在啥地方?XPO的能力展现就是要简化这种烦琐的与数据库交互的工作。当您执行这个指南1的事例代码,你也许会注意到一个叫做Tutorial1.mdb的文件出现在与Tutorial1.exe 相同的目录。这就是你的数据库。当然,如果你
想精确的控制该数据库的细节,也是完全没问题的。
1.1.4 从数据库重新获取持久化对象
您通过创建XPCollection可以重新获取全部持久化对象,并且可以指定您想获取的指定类型的对象。下面的例子返回了所有的客户对象:
[C#]
foreach(Customer theCustomer in new XPCollection(typeof(Customer))) {
Console.WriteLine(\"\\nCustomer Id: \" + theCustomer.Oid.ToString() + \"\\nCustomer Name: \" + theCustomer.Name +
\"\\nCompany: \" + theCustomer.CompanyName +
\"\\nPhone: \" + theCustomer.Phone +
\"\\nFax: \" + theCustomer.Fax + \"\\n\" );
}
2. 指南二
本指南讲述如何在持久化对象之间创建关系。关系的种类繁多。XPO支持一对一、一对多以及多对多等关系。本指南的例子会创建一对多和多对多关系。
2.1 定义一对多关系
对象之间可以发生关系。举个例,你可能拥有一个客户对象和一个订单对象。每一个客户可以拥有一个或多个关联的订单,每一张订单只能对应一个客户。
当一个对象被关联到其他对象时,您通常是创建一个数组或者一个ILIST属性来列举出被关联的对象。而,通过XPO的XPCOLLECTION类就可以在关系的结尾处,定义一对多关系的“多”。
为了举例说明如果通过两种类型的属性创建一对多的关系,在本指南,将在“客户“例子中创建两个附加的对象。第一个是address对象,它包含了一个string变量来描述customer的street address
;第二个是order对象,它包含一个order的详细信息。
一个customer很可能拥有多个address,也可能一个customer从一些地址里搬了出来同时另一个customer要住进来。因此,最好是赋予任意数量的address给特定的、不会被删除的customer。看下面的例子,它给Customer创建一个XPCollection类型的address属性,返回GetCollection方法的结果。
[C#]
public class Customer : XPObject {
...
[Association(\"CustomerAddresses\
public XPCollection Addresses { get { return GetCollection(\"Addresses\"); } }
...
}
上面的例子中,关于address属性的一对多属性在AssociationAttribute.中有注解。关系属性中有两个注意点。第一个是关系的名字;另一个是被连接的对象的类型。
你可以在address类里指定其他的关系。下面的例子就是在address类中创建一个Customer属性。
[C#]
[Association(\"CustomerAddresses\")]
public Customer Customer;
注意到这个以AssociationAttribute注解的Customer属
性,关系的名字是相同的。这个被关联对象的类型被省略是因为它已经通过这个属性的类型被指定过了。
Order对象与customer对象间拥有一个类似的关系,只有一个小区别。因为,当保存Order给一个已经删除的customer是没有意义的,所以,customer类的order属性需要通过Aggregated attribute来注解。
[C#]
public class Customer : XPObject {
...
[Association(\"CustomerOrders\
public XPCollection Orders { get { return GetCollection(\"Orders\"); } }
...
}
2.2 操作“关系”
当你的对象之间有确定的关系之后,你可以通过类的连接属性,很轻易访问它们, XPO加载任何你想在数据库操作的对象。下面的例子中会返回所有的customer对象和它们关联到的order对象。
[C#]
foreach(Order theOrder in theCustomer.Orders) {
Console.WriteLine(\"---Order: Id: \" + theOrder.Oid +
\
\
\
\
}
2.3 给一个关系添加对象
给一个关系添加对象时,您可以有两种选择。一种是将一个子对象的属性赋给它的父对象。如下:
[C#]
Customer myCustomer = new Customer(\"Mario Esprito\
\"(111) 345 6777\
Order myOrder = new Order(new DateTime(1980, 2, 3),
new DateTime(1990, 10, 4), new DateTime(1992, 10, 4), 2, 12.5M);
myOrder.Customer = myCustomer;
另一种是把子对象赋给一个父对象的collection。如下:
[C#]
myCustomer.Orders.Add(myOrder);
2.4 查询被关联对象
XPO提供了一个标准的对象用于查询一个数据库。当您要重新获取一个对象集合,您可以指定一个标准用来匹配。下面的例子中,设想您想找出那些运费少于10个货币单位的关联orders
[C#]
XPCollection orders = new XPCollection(typeof(Order), new
BinaryOperator(\"Freight\
3. 指南三:映射继承的层级
持久化对象是完全支持继承和多态的,所以你可以重新获取一个基类的集合,并处理实体类的实例。例如,如果有一个Manager对象继承自Employee对象的继承层级,这时你提交一个对employees的查询,将同时返回Manager对象和Employee对象集合。在关系数据库中有若干种映射继承关系的方法。在本指南中,默认是使用XPO手段。这样,XPO在一张表中存储了基类的属性,子类的属性存储在各自的表里。XPO会自动的安排好所有的映射继承属性。你只需定义类和关系即可。
[C#]
public class Employee : XPObject {
public string LastName = \"\";
public string FirstName = \"\";
[Association(\"ManagerEmployees\")]
public Manager Manager = null;
public Employee() {}
public Employee(string newLastName, string newFirstName) {
LastName = newLastName;
FirstName = newFirstName;
}
}
public class Manager : Employee
{
[Association(\"ManagerEmployees\
public XPCollection Employees {
get { return GetCollection(\"Employees\"); }
}
public Manager() {}
public Manager(string newLastName, string newFirstName) :
base(newLastName, newFirstName) {}
}
假设你想拥有一个被大多业务类继承的基类,但是又不想仅仅一张表对应所有的对象。这种情况的话,你只能用非持久属性来标注你的基类对象。
4.指南4掌握seesions
一个数据库要运作起来,通常你要指定连接属性,比如数据库名,用户名和密码。之前的指南中没有讲述上述数据库的细节要求,这可能是由于XPO的默认设置。XPO默认是使用MS ACCESS OLEDB PROVIDER,假设数据库名和应用程序名字相同,并且存放在应用程序的文件夹。如果数据库不存在,XPO会创建它。
如果您想覆写默认的方法,您可为Session.DefaultSession指定连接字符串或者创建连接对象或者创建Session对象。
要想运作您的Session对象,你得把它传给您的持久对象的构造函数,并调用基类构造函数,Session对象传给基类构造函数。
[C#]
public class Customer: XPObject {
public string Name = \"\";
public string CompanyName = \"\";
public string Phone = \"\";
public string Fax = \"\";
public Customer(Session session) : base(session) {}
}
现在您可以创建一个Session对象并且指定它的Session.ConnectionString.这个Session对象在您第一次加载或者保存持久对象时会自动连上数据库。如果你想显示的连接数据库,你可以调用Session.Connect方法,如下:
[C#]
Session = new Session();
session2.AutoCreateOptions = AutoCreateOptions.SchemaOnly;
session2.ConnectionString ID=Admin;Data Source=\" +
= \"Provider=Microsoft.Jet.OLEDB.4.0;User
\"SessionExample2_cs.mdb;Mode=Share Deny None;\";
session2.Connect();
您可以通过Session.AutoCreateOption.来控制数据库的自动创建。上面的例子中,我们不想session2对象去自动创建数据库,因此如果数据库不存在的话,Session.Connect方法会抛出异常。
5. 指南5 查询数据库
通过查询数据库可以获得到指定的数据并且将它暂时存贮在临时数据池中,为了下一
步的计划与用途。在XPO中,查询的结果是用XPCOLLECTION对象来呈现,XPCOLLECTION对象被定义成从给定的数据库中获取数据,并且运用适当的过滤标准。这些标准就是一些逻辑表达式,被运用到数据过滤。
为了举例说明如何定义查询,下面的例子创建了若干customer对象,并且通过XPCOLLECTION中标准操作,获得指定的一些customer对象。
[C#]
... new XPCollection(typeof(Customer),
new BinaryOperator(\"BirthDate\new DateTime(1960, 1, 2),
BinaryOperatorType.Less))
上例中,通过BinaryOperator.,一个简单的标准就创建了。想定义更加复杂的标准,,如下:
[C#]
GroupOperator criteria = new GroupOperator();
criteria.Operands.Add(new BinaryOperator(\"BirthDate\2), BinaryOperatorType.Less));
criteria.Operands.Add(new BinaryOperator(\"Address.Street\
... new XPCollection(typeof(Customer), criteria)
6. 指南6 使用延迟加载技术
本指南中,customer类拥有一个扩展的附加属性。这个属性也许包括word文档处理或者图片的传真或者未处理的数据。出于最优化思想考虑,这个属性在持久对象初始化后将被延迟。为了实现延迟,你必须在对象中声明一个私有的XPDelayedProperty字段,并为需要延迟的属性指定DelayedAttribute属性,然后对它执行get和set操作。
[C#]
public class Customer: XPObject {
...
private XPDelayedProperty document = new XPDelayedProperty();
[Delayed(\"document\")]
public Byte[] Attachment {
get { return (Byte[])document.Value; }
set { document.Value = value; }
}
}
7. 7. 指南7:运行事务
XPO象Microsoft ADO.NET一样提供对事务的支持。您通过适当的session方法,轻易的创建一个事务,然后提交它或者回滚它。
[C#]
class Account: XPObject {
public double Amount = 0;
protected override void BeforeSave() {
base.BeforeSave();
if (Amount < 0) {
throw new Exception(\"Negative amount\");
}
}
}
...
void TransferAmount(double amount) {
Account account = new Account();
Session.DefaultSession.BeginTransaction();
try {
account.Amount = amount;
account.Save();
Session.DefaultSession.CommitTransaction();
}
catch (Exception e) {
Session.DefaultSession.RollbackTransaction();
account.Reload();
}
}
8 指南8 使用乐观并发
在乐观并发模式下,会给数据池的访问上一把锁。这把锁会防止住一些其他用户企图根新与此同时。数据总是可用的除非在进行一个急需的修改操作。
当一个修改操作进行时,数据池中这个被改变的对象的原始版本会拿来与现在存在的对象相比较。如果2者不相同,更新就失败了。这个是取决于你如何运用你创建的业务逻辑来协调这两个对象。
通过XPO,你可以访问Session.LockingOption属性来设置session锁选项。
[C#]
class EasyObject: XPObject {
public string Name;
public EasyObject(Session session) : base(session) {}
}
...
void Main() {
//Creating an easyObject
Session.DefaultSession.LockingOption = LockingOption.Optimistic;
EasyObject easyObject = new EasyObject(Session.DefaultSession);
easyObject.Save();
//Creating an optimistic locking session
Session OptimisticLockingSession = new Session();
OptimisticLockingSession.LockingOption = LockingOption.Optimistic;
OptimisticLockingSession.ConnectionString Session.DefaultSession.ConnectionString;
//Loading the same easyObject in the optimistic locking session
EasyObject sameEasyObject (EasyObject)OptimisticLockingSession.GetObjectByKey(typeof(EasyObject), easyObject.Oid);
//Changing and saving the easyObject in the default session
=
=
easyObject.Name = \"easyObject 1\";
easyObject.Save();
//Changing and trying to save the easyObject in the optimistic locking session
sameEasyObject.Name = \"easyObject 2\";
try {
sameEasyObject.Save();
}
catch (LockingException) {
//It's impossible to save the easyObject because it is already changed in the default session
}
//Reloading the easyObject in the optimistic locking session
sameEasyObject.Reload();
//Changing and saving the easyObject in the optimistic locking session
sameEasyObject.Name = \"easyObject 2\";
sameEasyObject.Save();
}
9 指南9: 使用可分页集合
不同于,xpcursor提供一种新的获取和列举集合内容的方法。Xpcursor把整个集合分割成为子集合,而不是一下子就装载全部。每一页的对象数量是由XPCursor.PageSize的值来度量,因而存储空间的大小使用完全可以人为控制。下面的例子展示了XPCOLLECTION和Xpcursor实例在存储空间的使用上的比较。
首先,这些对象需要被创建,并持久化数据库。
[C#]
int i;
string dataString = new String('?', 1024);
Session.DefaultSession.ClearDatabase();
Console.WriteLine(\"Creating objects\");
for(i = 0; i<1000; ++i) {
SampleObject theObject = new SampleObject();
theObject.Data = dataString;
theObject.Save();
}
然后我们通过XPCOLLECTION和Xpcursor的内容重申并修改获得到的对象的值。
[C#]
GC.Collect();
i = 0;
Console.WriteLine(\"Processing objects with XPCursor\");
XPCursor cursor = new XPCursor(Session.DefaultSession,
typeof(SampleObject));
cursor.PageSize = 100;
foreach(SampleObject theObject in cursor) {
theObject.Data = new String('!', 1024);
theObject.Save();
++i;
if(i % 100 == 0)
Console.WriteLine(String.Format(\" GC.GetTotalMemory(true)));
Object {0}, memory allocated {1}\i,
}
GC.Collect();
i = 0;
Console.WriteLine(\"Processing objects with XPCollection\");
using(XPCollection collection = new XPCollection(Session.DefaultSession, typeof(SampleObject))) {
foreach(SampleObject theObject in collection) {
theObject.Data = new String('@', 1024);
theObject.Save();
++i;
if(i % 100 == 0)
Console.WriteLine(String.Format(\" GC.GetTotalMemory(true)));
Object {0}, memory allocated {1}\i,
}
}
从上面的结果我们可以看到,xpcursor改进了为对象集合分配存储空间的手段。Xpcursor的运用让您大大的降低了获取对象集合内容时对时间和存储空间的要求。
10.指南10:使用结构
从1.5版开始,XPO开始支持结构属性。本章讲述如何存储以及获取这种属性同时如何在他们的基础上搭建查询标准。
[C#]
public struct Point {
[Persistent(\"Abscissa\")]
public int X;
public int Y;
}
public class Shape: XPObject {
public string Name = \"\";
[Persistent(\"Location\")]
public Point Position;
}
默认情况下,结构类型属性不能存储在数据库中,除非它被PersistentAttribute.属性标记。这就是为什么上面的Position属性被这个PersistentAttribute.属性标记。通过传递一个持久化的属性作为参数给attribute,您可以轻易的映射一个类的模型到一个实际存在的数据库。本章中,‘X’结构成员将用持久化Attribute指定的名称为Abscissa'的数据列,而‘Y’成员则以名称为‘LocationY’存储。这类名称是由结构属性名和结构成员本身名组合而成的。结构成员可以象下面所示进行存储:
[C#]
Shape shape1 = new Shape();
shape1.Name = \"Ellipse\";
shape1.Position.X = 1;
shape1.Position.Y = 2;
shape1.Save();
你可以自由的构建标准查询来获取数据集合对象。下面的例子是实现如何查询Shapes数据库中Position.Y=1的数据集:
[C#]
... new XPCollection(typeof(Shape), new BinaryOperator(\"Position.X\
深层指导
1如何定义数据库连接字符串
Session.ConnectionString通过session对象提供了连接数据库的基本信息。您可为Session.DefaultSession指定ConnectionString属性,或者创建您自个的session对象。
批注:另一种定义session的方法是将Session.Connection属性与已经存在的OleDbConnection 或者 SqlConnection连接起来。
使用指定的数据库连接信息分配给Session.ConnectionString属性。
例如,要连接msaccess数据库:
String.Format(\"Provider=Microsoft.Jet.OLEDB.4.0;User ID={0};Data
Source={1};Mode=Share Deny None;\
要连接ms SQL Server数据库:
String.Format(\"user id={0};password={1};initial source={3};Connect Timeout={4}\userName, password, connectTimeout)
catalog={2};data
database, server,
因篇幅问题不能全部显示,请点此查看更多更全内容