DA20 - Data Abstract Adapters
本文说明什么是
Data Abstract Adapters
,
如何运行
,
以及
XML Adapter
可用于与
.Net, Java
或其他支持
XML
操作的语言生成的系统交换数据的
新特性
.
Data Adapters
Data Adapters
是一个
Data Abstract
架构中的支持数据特定格式化并在网络传输和本地存储的组件
.
此外
, data adapters
也可以同样处理数据表的
Delta
信息
.
Data Abstract
提供了两个
Data Adapter:
- TDABINAdapter: 将数据集数据转换为适当的二进制格式.这个Adapter是最快的一个也是在不需要考虑与外部系统互用时的首选.
- TDAXMLAdapter: 将数据集数据转换为XML文档. 这个XML格式是Data Abstract特有的,但是这个组件应用XSLT 轻松转化为其他格式
虽然你可以使用
data adapter
做其他任务
(
例如使用
XML Adapter
将数据集数据转化为
HTML
页面
),
但是它们通常用于客户端的
Data Tables
以及服务端的远程服务
(
见
ServiceAdapter
属性
). Data Tables
和
DARemoteServices
需要
data adapters
指定如何序列化或反序列化数据
.
所有的
data adapters
继承于
TDADataAdapter
(uDADataTable.pas
单元
).
TDADataAdapter
提供了所有写入或读取
Adapter
的必要方法
.
下面的代码展示了如何使用
XML Data Adapter
序列化两个查询
(Schema
中预先定义的
Customers
和
Orders
)
的数据
:
var
conn : IDAConnection;
orders, customers : IDADataset;
xmlstream : TMemoryStream;
begin
xmlstream := TMemoryStream.Create;
try
// Opens a database connections and queries for the two tables
conn := ConnectionManager.NewConnection(
'ADO'
);
customers := Schema.NewDataset(conn, ds_Customers);
orders := Schema.NewDataset(conn, ds_Orders);
// Writes the data into the stream by using the XML Adapter
XMLAdapter.WriteXSLT := NIL;
// In case there's one set
XMLAdapter.Initialize(xmlstream, aiWrite);
XMLAdapter.WriteDataset(customers, [woSchema, woRows]);
XMLAdapter.WriteDataset(orders, [woSchema, woRows]);
XMLAdapter.Finalize;
[..]
执行这段代码后
, xmlstream
流中将包含如下格式的
XML
文档
:
<
XMLData
><
Schema
><
Datasets
><
Customers
><
Fields
>
<
Field
Alignment
="
taLeftJustify
"
BlobType
="
dabtUnknown
"
BusinessRulesID
=""
Calculated
="
False
"
CustomAttributes
="
10370684
"
DataType
="
datAutoInc
"
DefaultValue
=""
Description
=""
DictionaryEntry
=""
DisplayFormat
=""
DisplayLabel
="
CustomerIdx
"
DisplayWidth
="
0
"
EditFormat
=""
EditMask
=""
GeneratorName
=""
InPrimaryKey
="
True
"
KeyFields
=""
LogChanges
="
True
"
Lookup
="
False
"
LookupCache
="
False
"
LookupKeyFields
=""
LookupResultField
=""
LookupSource
="
0
"
Name
="
CustomerIdx
"
ReadOnly
="
False
"
RegExpression
=""
Required
="
True
"
ServerAutoRefresh
="
False
"
Size
="
0
"
Visible
="
True
"/>
<
Field
Alignment
="
taLeftJustify
"
BlobType
="
dabtUnknown
"
BusinessRulesID
=""
Calculated
="
False
"
CustomAttributes
="
10370916
"
DataType
="
datString
"
DefaultValue
=""
Description
=""
DictionaryEntry
=""
DisplayFormat
=""
DisplayLabel
="
FirstName
"
DisplayWidth
="
0
"
EditFormat
=""
EditMask
=""
GeneratorName
=""
InPrimaryKey
="
False
"
KeyFields
=""
LogChanges
="
True
"
Lookup
="
False
"
LookupCache
="
False
"
LookupKeyFields
=""
LookupResultField
=""
LookupSource
="
0
"
Name
="
FirstName
"
ReadOnly
="
False
"
RegExpression
=""
Required
="
True
"
ServerAutoRefresh
="
False
"
Size
="
20
"
Visible
="
True
"/>
[..]
</
Fields
></
Customers
>
<
Orders
><
Fields
>
[..]
<
Field
Alignment
="
taLeftJustify
"
BlobType
="
dabtUnknown
"
BusinessRulesID
=""
Calculated
="
False
"
CustomAttributes
="
10407460
"
DataType
="
datDateTime
"
DefaultValue
=""
Description
=""
DictionaryEntry
=""
DisplayFormat
=""
DisplayLabel
="
InsertDate
"
DisplayWidth
="
0
"
EditFormat
=""
EditMask
=""
GeneratorName
=""
InPrimaryKey
="
False
"
KeyFields
=""
LogChanges
="
True
"
Lookup
="
False
"
LookupCache
="
False
"
LookupKeyFields
=""
LookupResultField
=""
LookupSource
="
0
"
Name
="
InsertDate
"
ReadOnly
="
False
"
RegExpression
=""
Required
="
True
"
ServerAutoRefresh
="
False
"
Size
="
0
"
Visible
="
True
"/>
<
Field
Alignment
="
taLeftJustify
"
BlobType
="
dabtUnknown
"
BusinessRulesID
=""
Calculated
="
False
"
CustomAttributes
="
10407692
"
DataType
="
datDateTime
"
DefaultValue
=""
Description
=""
DictionaryEntry
=""
DisplayFormat
=""
DisplayLabel
="
ShipDate
"
DisplayWidth
="
0
"
EditFormat
=""
EditMask
=""
GeneratorName
=""
InPrimaryKey
="
False
"
KeyFields
=""
LogChanges
="
True
"
Lookup
="
False
"
LookupCache
="
False
"
LookupKeyFields
=""
LookupResultField
=""
LookupSource
="
0
"
Name
="
ShipDate
"
ReadOnly
="
False
"
RegExpression
=""
Required
="
False
"
ServerAutoRefresh
="
False
"
Size
="
0
"
Visible
="
True
"/>
[..]
</
Fields
></
Orders
></
Datasets
></
Schema
>
<
Datasets
><
Customers
>
<
Row
CustomerIdx
="
1
"
FirstName
="
Wilton
"
LastName
="
Forster
"
Address1
="
1371 Inventing Street
"
City
="
Jefferson
"
State
="
SC
"
<
Row
CustomerIdx
="
2
"
FirstName
="
Doyle
"
MiddleName
="
Barry
"
LastName
="
Acherman
"
Address1
="
3322 Widened Street
"
City
="
Mcallen
"
State
="
TX
"
Zip
="
64448
"
Phone1
="
(653) 818-8635
"
Fax
="
(364) 702-7820
"
<
Row
CustomerIdx
="
3
"
FirstName
="
Fanchon
"
LastName
="
Kuehler
"
Address1
="
6767 Sleepily Street
"
City
="
Killeen
"
State
="
MT
"
Zip
="
18460
"
Phone1
="
(742) 613-6096
"
Phone2
="
(459) 475-9756
"
[..]
</
Customers
>
<
Orders
>
[..]
<
Row
OrderIdx
="
14466
"
CustomerIdx
="
6
"
ShipperIdx
="
3
"
TotalPrice
="
47555.93
"
ShippingCost
="
66.98
"
InsertedBy
="
10
"
InsertDate
="
11/5/2003 11:20:27 AM
"
ShipDate
="
11/8/2003 11:20:27 AM
"/>
<
Row
OrderIdx
="
14559
"
CustomerIdx
="
3
"
ShipperIdx
="
4
"
TotalPrice
="
39819.58
"
ShippingCost
="
40.51
"
InsertedBy
="
10
"
InsertDate
="
9/17/2003 5:10:17 AM
"
ShipDate
="
9/21/2003 5:10:17 AM
"/>
<
Row
OrderIdx
="
14566
"
CustomerIdx
="
4
"
ShipperIdx
="
5
"
TotalPrice
="
94003
"
ShippingCost
="
67.94
"
InsertedBy
="
5
"
InsertDate
="
3/3/2004 5:05:27 PM
"
ShipDate
="
3/8/2004 5:05:27 PM
"/>
<
Row
OrderIdx
="
14725
"
CustomerIdx
="
9
"
ShipperIdx
="
3
"
TotalPrice
="
36270.27
"
ShippingCost
="
60.77
"
InsertedBy
="
7
"
InsertDate
="
7/22/2003 6:51:48 PM
"
ShipDate
="
7/25/2003 6:51:48 PM
"/>
</
Orders
></
Datasets
></
XMLData
>
这里只显示其中部分条目的信息
,
完全的文件
(DatasetSample.xml)
请见本文上面的代码连接
.
如果你要从这个
XML
文件的内容中重新获取这两个数据集
,
代码如下
:
// Loads the data in the data tables
XMLAdapter.Initialize(xmlstream, aiRead);
XMLAdapter.ReadDataset(ds_Orders, dtOrders, TRUE);
XMLAdapter.ReadDataset(ds_Customers, dtCustomers, TRUE);
XMLAdapter.Finalize;
如果你需要保存这两个数据表的变更
Delta,
你必须使用
WriteDelta
和
ReadDelta
方法
.
例如
:
var
xmlstream : TMemoryStream;
[..]
begin
[..]
xmlstream := TMemoryStream.Create;
try
// Generates some test updates (ask confirmation first)
CreateTestUpdates;
// Erases the XSLT in case there's one set
XMLAdapter.WriteXSLT := NIL;
// In case there's one set
// Writes the data table deltas into the stream
// by using the XML Adapter
XMLAdapter.Initialize(xmlstream, aiWrite);
XMLAdapter.WriteDelta(dtCustomers);
XMLAdapter.WriteDelta(dtOrders);
XMLAdapter.Finalize;
这段代码执行后
,xmlstream
中将包含如下格式的
XML
文档
:
<
XMLData
><
Schema
><
Deltas
><
Customers
><
LoggedFields
>
<
Field
Name
="
CustomerIdx
"
DataType
="
datAutoInc
"/>
<
Field
Name
="
FirstName
"
DataType
="
datString
"/>
<
Field
Name
="
MiddleName
"
DataType
="
datString
"/>
[..]
</
LoggedFields
>
<
KeyFields
><
Field
Name
="
CustomerIdx
"/></
KeyFields
></
Customers
>
<
Orders
><
LoggedFields
>
<
Field
Name
="
OrderIdx
"
DataType
="
datAutoInc
"/>
<
Field
Name
="
CustomerIdx
"
DataType
="
datInteger
"/>
[..]
</
LoggedFields
>
<
KeyFields
><
Field
Name
="
OrderIdx
"/></
KeyFields
>
</
Orders
></
Deltas
></
Schema
>
<
Deltas
>
<
Customers
>
<
Row
><
RecID
>
10
</
RecID
><
ChangeType
>
ctDelete
</
ChangeType
>
<
Status
>
csPending
</
Status
><
Message
></
Message
><
OldValues
CustomerIdx
="
10
"
FirstName
="
Hester
"
MiddleName
=""
LastName
="
Rivera
"
Address1
="
11275 Prematurity Lane
"
Address2
=""
City
="
Turner
"
State
="
IL
"
Zip
="
40587
"
Phone1
="
(717) 345-9144
"
Phone2
=""
Fax
=""
<
NewValues
CustomerIdx
=""
FirstName
=""
MiddleName
=""
LastName
=""
Address1
=""
Address2
=""
City
=""
State
=""
Zip
=""
Phone1
=""
Phone2
=""
Fax
=""
Email
=""
CreditCard
=""/></
Row
>
<
Row
><
RecID
>
11
</
RecID
><
ChangeType
>
ctInsert
</
ChangeType
>
<
Status
>
csPending
</
Status
><
Message
></
Message
><
OldValues
CustomerIdx
=""
FirstName
=""
MiddleName
=""
LastName
=""
Address1
=""
Address2
=""
City
=""
State
=""
Zip
=""
Phone1
=""
Phone2
=""
Fax
=""
Email
=""
CreditCard
=""/><
NewValues
CustomerIdx
="
-1
"
FirstName
="
John
"
MiddleName
=""
LastName
="
Smith
"
Address1
="
202 North Lake Drive
"
Address2
=""
City
="
Barrington
"
State
="
IL
"
Zip
="
60010
"
CreditCard
="
3333-2222-1111-2
"/></
Row
>
[..]
</
Customers
>
<
Orders
>
<
Row
><
RecID
>
113
</
RecID
><
ChangeType
>
ctDelete
</
ChangeType
>
<
Status
>
csPending
</
Status
><
Message
></
Message
><
OldValues
OrderIdx
="
12078
"
CustomerIdx
="
8
"
ShipperIdx
="
3
"
TotalPrice
="
30925.13
"
ShippingCost
="
64.07
"
InsertedBy
="
9
"
InsertDate
="
7/17/2003 9:34:56 AM
"
ShipDate
="
7/20/2003 9:34:56 AM
"/>
<
NewValues
OrderIdx
=""
CustomerIdx
=""
ShipperIdx
=""
TotalPrice
=""
ShippingCost
=""
InsertedBy
=""
InsertDate
=""
ShipDate
=""/></
Row
>
<
Row
><
RecID
>
114
</
RecID
><
ChangeType
>
ctDelete
</
ChangeType
>
<
Status
>
csPending
</
Status
><
Message
></
Message
>
<
OldValues
OrderIdx
="
12552
"
CustomerIdx
="
8
"
ShipperIdx
="
4
"
TotalPrice
="
78890.59
"
ShippingCost
="
50.37
"
InsertedBy
="
7
"
InsertDate
="
11/5/2003 6:45:39 AM
"
ShipDate
="
11/9/2003 6:45:39 AM
"/>
<
NewValues
OrderIdx
=""
CustomerIdx
=""
ShipperIdx
=""
TotalPrice
=""
ShippingCost
=""
InsertedBy
=""
InsertDate
=""
ShipDate
=""/></
Row
>
[..]
</
Orders
></
Deltas
></
XMLData
>
如上面的
,
完全文件
(DeltaSample.xml)
可见本文上面的源码连接
.
为了从这个
XML
文档中重新生成两个初始的
Delta,
必须写如下代码
:
var
xmlstream : TMemoryStream;
customersdelta,
ordersdelta : IDADelta;
begin
[..]
// Reads the deltas from the stream
customersdelta := NewDelta(ds_Customers);
ordersdelta := NewDelta(ds_Orders);
xmlstream.Position :=
0
;
XMLAdapter.Initialize(xmlstream, aiRead);
XMLAdapter.ReadDelta(
'Customers'
, customersdelta);
XMLAdapter.ReadDelta(
'Orders'
, ordersdelta);
XMLAdapter.Finalize;
可见
Data Abstract data adapter
可以向流中写入多个数据集或
Delta
以便于在客户端与服务端交换数据时节省网络请求
.
上面这些代码可以看作与
XML adapter
是独立的
: binary adapter
也使用同样的代码处理
.
提示
:
唯一不同的地方就是当你直接使用
XML adapter
的特有属性如
Write/ReadXSLT.
如果你希望保持代码的兼容性
,
可以按下面的方式写代码
:
if
(MyAdapter is TDAXMLAdapter)
then TDAXMLAdapter(MyAdapter).WriteXSLT.LoadFromFile :=
'c:/test.xsl'
;
XML
格式和
XSLT
转化
XML Data Adapter
的格式非常简单
,
其结构如下
:
<
XMLData
>
<
Schema
>
<
Datasets
>
(this section contains the fields definitions of each dataset
contained in the document)
</
Datasets
>
<
Deltas
>
(this section contains the definitions of each delta contained
in the document: the list of the logged fields, their types
and the key fields)
</
Deltas
>
</
Schema
>
<
Datasets
>
(this section contains the actual data of the datasets)
</
Datasets
>
<
Deltas
>
(this section contains the actual data of the deltas which
includes information such as change status, message, type, etc.)
</
Deltas
>
</
XMLData
>
依赖于我们写入数据流
(
通过
WriteDataset
或
WriteDelta
方法
)
的不同内容上面所示的部分可能不包含在最终文档中
.
例如
,
如果我们不写入
Delta,
将不会显示
XMLData/Schema/Deltas
或
XMLData/Deltas.
应该去查看显示的元素而不是假设如何如何
.
这种格式很清晰
,
可用于与已经使用其它格式的系统交换数据
.
例如
,
可能会要求返回
RosettaNet
标准的
XML
格式的数据
(http://www.rosettanet.org/).
XML Adapter
允许你使用
XSLT
脚本与其它格式相互转化
.
如果你对
XSLT
标准不熟悉
,
请看
:
http://www.codeguru.com/Csharp/Csharp/cs_data/xml/article.php/c7801/ (XSLT
指南
, Geoffrey Slinker)
http://maple.cc.kcl.ac.uk/XSLT/ (XSLT
指南
, John Bradley)
XSLT
范例带了两个
XSTL
例子将
Customers
数据转换为不同格式的
XML
上面的数据包含在
CustomersToSimpleXML.xsl (
见本文上面的代码连接
).
Customer
数据转换为
HTML
页面
:
也在代码连接中查看
CustomersToHTML.xsl XSLT
文件
.