在上篇Blog中介绍了如何定义一个与DataRow相结合的数据类,那么本篇将介绍如何定义一个与DataTable对应的数据集合。
在DotNet中提供了一个CollectionBase作为我们定义强类型的数据集合的抽象类,在DotNet1.1中要定义一个强类型的数据集合就必须为每一种数据类定义一个对应的数据集合,在2.0中增加了泛型的功能后,这个问题得到了解决。又由于在目前的Ibatisnet版本中还不支持泛型的功能,所以数据集合可以选择从ArrayList或CollectionBase继承下来。但是不管是ArrayList还是CollectionBase都不支持序列化,也是他们都有没有Serializable属性,那么实现的数据集合也将无法实现序列化,所以这边选择直接实现IList接口,内部再实例化一个ArrayList做为数据容器。类的定义如下:
public class ObjectList : IList, ISerializable{}
还有一需要解决的问题是,数据类如何与DataTable对应起来呢?在数据类定义一个DataTable的属性和内部变量,做为存储数据的容器。
private DataTable m_dataTable = null;
/// <summary>
/// Gets the data table form.
/// </summary>
/// <value>The data table form.</value>
public DataTable DataTableForm
{
get { return m_dataTable; }
}
因为前面有提到了,一个对象对应一个DataRow,当前一个对象单独存在时,它的数据存放在数据类的数据容器里,而当中被加到一个集合里时,数据行就应该存放在数据集合对应的DataTable里了。那要怎么转换呢?很简单,只需要把数据行从原来(数据类的数据容器)的表里面复制到ObjectList对应的DataTable里,然后将原来的行删除就行了。这里复制一行数据也是有学问的,因为一个DataRow一旦创建了,它就只能被加入到创建它的那个DataTable里,当它被加入到另外一个表里就会抛出它同时只能属于一个表的异常,而如果是DataRow里的数据一列一列地复制到另一个DataRow,就会对性能造成非常大的影响。最理想的办法就是数据不动,只改变DataRow记录的一个状态信息就行了。这里的改变行状态的办法就是NewRow,而数据不动的办法就是将源Row的ItemArray属性赋值给目的的ItemArray。经过测试,这样做可以减少1倍以上的时间成本(内存成本也一样)。
具体的添加方法如下:
同时增加一个反序列化的构造函数
protected ObjectList(SerializationInfo info, StreamingContext context) : base()
{
m_dataTable = info.GetValue("DataTable", typeof(DataTable)) as DataTable;
Type m_dataObjectType = info.GetValue("DataObjectType", typeof(Type)) as Type;
if (m_dataObjectType != null)
{
foreach (DataRow m_dr in m_dataTable.Rows)
{
m_list.Add(Activator.CreateInstance(m_dataObjectType, m_dr));
}
}
}
整个数据类的定义如下:
[Serializable]
/// Initializes a new instance of the <see cref="T:ObjectList"/> class.
/// </summary>
public ObjectList1()
{
m_list = new ArrayList();
}
/// <summary>
/// Gets the data table form.
/// </summary>
/// <value>The data table form.</value>
public DataTable DataTableForm
{
get { return m_dataTable; }
}
private void AddObjectRowToListTable(IDataObject p_dataObject)
{
if (m_dataTable == null)
m_dataTable = p_dataObject.DataContainer.Clone();
DataRow m_newRow = m_dataTable.NewRow();
/***********************************************
* 使用上面代码时间性能会比下面的高一倍
* for (int i = 0; i < p_dataObject.ObjectRow.ItemArray.Length; i++)
{
m_newRow[i] = p_dataObject.ObjectRow.ItemArray[i];
}
* ********************************************/
m_dataTable.Rows.Add(m_newRow);
p_dataObject.ObjectRow.Delete();
p_dataObject.ObjectRow.Table.AcceptChanges();
p_dataObject.ObjectRow = m_newRow;
}
42 IList Members
164 ICollection Members
212 IEnumerable Members
227 protected ObjectList1(SerializationInfo info, StreamingContext context)
{
229 m_dataTable = info.GetValue("DataTable", typeof(DataTable)) as DataTable;
230 Type m_dataObjectType = info.GetValue("DataObjectType", typeof(Type)) as Type;
231 if (m_dataObjectType != null)
232 {
234 foreach (DataRow m_dr in m_dataTable.Rows)
235 {
236 m_list.Add(Activator.CreateInstance(m_dataObjectType,m_dr));
237 }
238 }
239 }
240 ISerializable Members
253 }
1private void AddObjectRowToListTable(IDataObject p_dataObject)
2 {
3 if (m_dataTable == null)
4 m_dataTable = p_dataObject.DataContainer.Clone();
5 DataRow m_newRow = m_dataTable.NewRow();
6 m_newRow.ItemArray = p_dataObject.ObjectRow.ItemArray;
7 /***********************************************
8 * 使用上面代码时间性能会比下面的高一倍
9 * for (int i = 0; i < p_dataObject.ObjectRow.ItemArray.Length; i++)
10 {
11 m_newRow[i] = p_dataObject.ObjectRow.ItemArray[i];
12 }
13 * ********************************************/
14
15 m_dataTable.Rows.Add(m_newRow);
16 p_dataObject.ObjectRow.Delete();
17 p_dataObject.ObjectRow.Table.AcceptChanges();
18 p_dataObject.ObjectRow = m_newRow;
19 }
下一个就是序列化的问题了。序列化集合类好像比较麻烦,因为它本身并没有为我提供支持序列化的方法。而在这个数据集合里,实现了ISerializable接口,由我们自己来定义要序列的方式。我们的关键是序列化数据,所以就这里的序列化就只需要序列ObjectList对应的DataTable就行了。实现ISerializable接口如下:
1public void GetObjectData(SerializationInfo info, StreamingContext context)
2 {
3 if (this.Count >= 0)
4 {
5 info.AddValue("DataObjectType", m_list[0].GetType()); //当前数据类的类型
6 }
7
8 info.AddValue("DataTable", this.m_dataTable, typeof(DataTable));
9 }
10
联系客服