在上篇Blog中介绍了如何定义一个与DataRow相结合的数据类,那么本篇将介绍如何定义一个与DataTable对应的数据集合。
在DotNet中提供了一个CollectionBase作为我们定义强类型的数据集合的抽象类,在DotNet1.1中要定义一个强类型的数据集合就必须为每一种数据类定义一个对应的数据集合,在2.0中增加了泛型的功能后,这个问题得到了解决。又由于在目前的Ibatisnet版本中还不支持泛型的功能,所以数据集合可以选择从ArrayList或CollectionBase继承下来。但是不管是ArrayList还是CollectionBase都不支持序列化,也是他们都有没有Serializable属性,那么实现的数据集合也将无法实现序列化,所以这边选择直接实现IList接口,内部再实例化一个ArrayList做为数据容器。类的定义如下:
public class ObjectList : IList, ISerializable{}
还有一需要解决的问题是,数据类如何与DataTable对应起来呢?在数据类定义一个DataTable的属性和内部变量,做为存储数据的容器。
1
private DataTable m_dataTable = null;
2
/**//// <summary>
3
/// Gets the data table form.
4
/// </summary>
5
/// <value>The data table form.</value> 6
public DataTable DataTableForm
7
{
8
get
{ return m_dataTable; }
9
}
10
因为前面有提到了,一个对象对应一个DataRow,当前一个对象单独存在时,它的数据存放在数据类的数据容器里,而当中被加到一个集合里时,数据行就应该存放在数据集合对应的DataTable里了。那要怎么转换呢?很简单,只需要把数据行从原来(数据类的数据容器)的表里面复制到ObjectList对应的DataTable里,然后将原来的行删除就行了。这里复制一行数据也是有学问的,因为一个DataRow一旦创建了,它就只能被加入到创建它的那个DataTable里,当它被加入到另外一个表里就会抛出它同时只能属于一个表的异常,而如果是DataRow里的数据一列一列地复制到另一个DataRow,就会对性能造成非常大的影响。最理想的办法就是数据不动,只改变DataRow记录的一个状态信息就行了。这里的改变行状态的办法就是NewRow,而数据不动的办法就是将源Row的ItemArray属性赋值给目的的ItemArray。经过测试,这样做可以减少1倍以上的时间成本(内存成本也一样)。
具体的添加方法如下:
1
private 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
}
20
下一个就是序列化的问题了。序列化集合类好像比较麻烦,因为它本身并没有为我提供支持序列化的方法。而在这个数据集合里,实现了ISerializable接口,由我们自己来定义要序列的方式。我们的关键是序列化数据,所以就这里的序列化就只需要序列ObjectList对应的DataTable就行了。实现ISerializable接口如下:
1
public 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
同时增加一个反序列化的构造函数
1
protected ObjectList(SerializationInfo info, StreamingContext context) : base()
2
{
3
m_dataTable = info.GetValue("DataTable", typeof(DataTable)) as DataTable;
4
Type m_dataObjectType = info.GetValue("DataObjectType", typeof(Type)) as Type;
5
if (m_dataObjectType != null)
6
{
7
foreach (DataRow m_dr in m_dataTable.Rows)
8
{
9
m_list.Add(Activator.CreateInstance(m_dataObjectType, m_dr));
10
}
11
}
12
}
13
这样就可以支持序列化与反序列化了。
整个数据类的定义如下:
1
[Serializable]
2
public class ObjectList1 : IList, ISerializable
3
{
4
private ArrayList m_list = null;
5
private DataTable m_dataTable = null;
6
/**//// <summary>
7
/// Initializes a new instance of the <see cref="T:ObjectList"/> class.
8
/// </summary>
9
public ObjectList1()
10
{
11
m_list = new ArrayList();
12
}
13
/**//// <summary>
14
/// Gets the data table form.
15
/// </summary>
16
/// <value>The data table form.</value>
17
public DataTable DataTableForm
18
{
19
get
{ return m_dataTable; }
20
}
21
private void AddObjectRowToListTable(IDataObject p_dataObject)
22
{
23
if (m_dataTable == null)
24
m_dataTable = p_dataObject.DataContainer.Clone();
25
DataRow m_newRow = m_dataTable.NewRow();
26
27
28
m_newRow.ItemArray = p_dataObject.ObjectRow.ItemArray;
29
/**//***********************************************
30
* 使用上面代码时间性能会比下面的高一倍
31
* for (int i = 0; i < p_dataObject.ObjectRow.ItemArray.Length; i++)
32
{
33
m_newRow[i] = p_dataObject.ObjectRow.ItemArray[i];
34
}
35
* ********************************************/
36
37
m_dataTable.Rows.Add(m_newRow);
38
p_dataObject.ObjectRow.Delete();
39
p_dataObject.ObjectRow.Table.AcceptChanges();
40
p_dataObject.ObjectRow = m_newRow;
41
}
42
IList Members#region IList Members
43
44
/**//// <summary>
45
/// Adds an item to the <see cref="T:System.Collections.IList"></see>.
46
/// </summary>
47
/// <param name="value">The <see cref="T:System.Object"></see> to add to the <see cref="T:System.Collections.IList"></see>.</param>
48
/// <returns>
49
/// The position into which the new element was inserted.
50
/// </returns>
51
/// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.IList"></see> is read-only.-or- The <see cref="T:System.Collections.IList"></see> has a fixed size. </exception>
52
public int Add(object value)
53
{
54
AddObjectRowToListTable((IDataObject)value);
55
return this.m_list.Add(value);
56
}
57
58
/**//// <summary>
59
/// Removes all items from the <see cref="T:System.Collections.IList"></see>.
60
/// </summary>
61
/// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.IList"></see> is read-only. </exception>
62
public void Clear()
63
{
64
this.m_list.Clear();
65
this.DataTableForm.Clear();
66
}
67
68
/**//// <summary>
69
/// Determines whether the <see cref="T:System.Collections.IList"></see> contains a specific value.
70
/// </summary>
71
/// <param name="value">The <see cref="T:System.Object"></see> to locate in the <see cref="T:System.Collections.IList"></see>.</param>
72
/// <returns>
73
/// true if the <see cref="T:System.Object"></see> is found in the <see cref="T:System.Collections.IList"></see>; otherwise, false.
74
/// </returns>
75
public bool Contains(object value)
76
{
77
return m_list.Contains(value);
78
}
79
80
/**//// <summary>
81
/// Determines the index of a specific item in the <see cref="T:System.Collections.IList"></see>.
82
/// </summary>
83
/// <param name="value">The <see cref="T:System.Object"></see> to locate in the <see cref="T:System.Collections.IList"></see>.</param>
84
/// <returns>
85
/// The index of value if found in the list; otherwise, -1.
86
/// </returns>
87
public int IndexOf(object value)
88
{
89
return m_list.IndexOf(value);
90
}
91
92
/**//// <summary>
93
/// Inserts an item to the <see cref="T:System.Collections.IList"></see> at the specified index.
94
/// </summary>
95
/// <param name="index">The zero-based index at which value should be inserted.</param>
96
/// <param name="value">The <see cref="T:System.Object"></see> to insert into the <see cref="T:System.Collections.IList"></see>.</param>
97
/// <exception cref="T:System.ArgumentOutOfRangeException">index is not a valid index in the <see cref="T:System.Collections.IList"></see>. </exception>
98
/// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.IList"></see> is read-only.-or- The <see cref="T:System.Collections.IList"></see> has a fixed size. </exception>
99
/// <exception cref="T:System.NullReferenceException">value is null reference in the <see cref="T:System.Collections.IList"></see>.</exception>
100
public void Insert(int index, object value)
101
{
102
this.m_list.Insert(index, value);
103
AddObjectRowToListTable((IDataObject)value);
104
}
105
106
/**//// <summary>
107
/// Gets a value indicating whether the <see cref="T:System.Collections.IList"></see> has a fixed size.
108
/// </summary>
109
/// <value></value>
110
/// <returns>true if the <see cref="T:System.Collections.IList"></see> has a fixed size; otherwise, false.</returns>
111
public bool IsFixedSize
112
{
113
get
{ return false; }
114
}
115
116
/**//// <summary>
117
/// Gets a value indicating whether the <see cref="T:System.Collections.IList"></see> is read-only.
118
/// </summary>
119
/// <value></value>
120
/// <returns>true if the <see cref="T:System.Collections.IList"></see> is read-only; otherwise, false.</returns>
121
public bool IsReadOnly
122
{
123
get
{ return false; }
124
}
125
126
/**//// <summary>
127
/// Removes the first occurrence of a specific object from the <see cref="T:System.Collections.IList"></see>.
128
/// </summary>
129
/// <param name="value">The <see cref="T:System.Object"></see> to remove from the <see cref="T:System.Collections.IList"></see>.</param>
130
/// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.IList"></see> is read-only.-or- The <see cref="T:System.Collections.IList"></see> has a fixed size. </exception>
131
public void Remove(object value)
132
{
133
((IDataObject)value).ObjectRow.Delete();
134
this.m_list.Remove(value);
135
}
136
137
/**//// <summary>
138
/// Removes the <see cref="T:System.Collections.IList"></see> item at the specified index.
139
/// </summary>
140
/// <param name="index">The zero-based index of the item to remove.</param>
141
/// <exception cref="T:System.ArgumentOutOfRangeException">index is not a valid index in the <see cref="T:System.Collections.IList"></see>. </exception>
142
/// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.IList"></see> is read-only.-or- The <see cref="T:System.Collections.IList"></see> has a fixed size. </exception>
143
public void RemoveAt(int index)
144
{
145
((IDataObject)this.m_list[index]).ObjectRow.Delete();
146
this.m_list.RemoveAt(index);
147
}
148
149
/**//// <summary>
150
/// Gets or sets the <see cref="T:Object"/> at the specified index.
151
/// </summary>
152
/// <value></value>
153
public object this[int index]
154
{
155
get
{ return this.m_list[index]; }
156
set
157
{
158
throw new Exception("The method or operation is not implemented.");
159
}
160
}
161
162
#endregion
163
164
ICollection Members#region ICollection Members
165
166
/**//// <summary>
167
/// Copies the elements of the <see cref="T:System.Collections.ICollection"></see> to an <see cref="T:System.Array"></see>, starting at a particular <see cref="T:System.Array"></see> index.
168
/// </summary>
169
/// <param name="array">The one-dimensional <see cref="T:System.Array"></see> that is the destination of the elements copied from <see cref="T:System.Collections.ICollection"></see>. The <see cref="T:System.Array"></see> must have zero-based indexing.</param>
170
/// <param name="index">The zero-based index in array at which copying begins.</param>
171
/// <exception cref="T:System.ArgumentNullException">array is null. </exception>
172
/// <exception cref="T:System.ArgumentOutOfRangeException">index is less than zero. </exception>
173
/// <exception cref="T:System.ArgumentException">array is multidimensional.-or- index is equal to or greater than the length of array.-or- The number of elements in the source <see cref="T:System.Collections.ICollection"></see> is greater than the available space from index to the end of the destination array. </exception>
174
/// <exception cref="T:System.InvalidCastException">The type of the source <see cref="T:System.Collections.ICollection"></see> cannot be cast automatically to the type of the destination array. </exception>
175
public void CopyTo(Array array, int index)
176
{
177
this.m_list.CopyTo(array, index);
178
}
179
180
/**//// <summary>
181
/// Gets the number of elements contained in the <see cref="T:System.Collections.ICollection"></see>.
182
/// </summary>
183
/// <value></value>
184
/// <returns>The number of elements contained in the <see cref="T:System.Collections.ICollection"></see>.</returns>
185
public int Count
186
{
187
get
{ return this.m_list.Count; }
188
}
189
190
/**//// <summary>
191
/// Gets a value indicating whether access to the <see cref="T:System.Collections.ICollection"></see> is synchronized (thread safe).
192
/// </summary>
193
/// <value></value>
194
/// <returns>true if access to the <see cref="T:System.Collections.ICollection"></see> is synchronized (thread safe); otherwise, false.</returns>
195
public bool IsSynchronized
196
{
197
get
{ return false; }
198
}
199
200
/**//// <summary>
201
/// Gets an object that can be used to synchronize access to the <see cref="T:System.Collections.ICollection"></see>.
202
/// </summary>
203
/// <value></value>
204
/// <returns>An object that can be used to synchronize access to the <see cref="T:System.Collections.ICollection"></see>.</returns>
205
public object SyncRoot
206
{
207
get
{ return this.m_list.SyncRoot; }
208
}
209
210
#endregion
211
212
IEnumerable Members#region IEnumerable Members
213
214
/**//// <summary>
215
/// Returns an enumerator that iterates through a collection.
216
/// </summary>
217
/// <returns>
218
/// An <see cref="T:System.Collections.IEnumerator"></see> object that can be used to iterate through the collection.
219
/// </returns>
220
public IEnumerator GetEnumerator()
221
{
222
return m_list.GetEnumerator();
223
}
224
225
#endregion
226
227
protected ObjectList1(SerializationInfo info, StreamingContext context)
228
{
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
{
233
m_list = new ArrayList();
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#region ISerializable Members
241
242
public void GetObjectData(SerializationInfo info, StreamingContext context)
243
{
244
if (m_list.Count >= 0)
245
{
246
info.AddValue("DataObjectType", this.m_list[0].GetType());
247
}
248
249
info.AddValue("DataTable", this.m_dataTable, typeof(DataTable));
250
}
251
252
#endregion
253
}
上面的数据类肯定还存在一些问题,目前没有更深入地去研究,有些地方可能还不是很合理,随着应用的深入,仍需要做一些改进。最后,如果认为这样使用很不爽,不能做到强类型的引用。所有的对象都只能认识到DataObjectBase这一级类型(因为所有的数据类都是这个抽象里继承下来)。我们可以定义一个泛型的集合对它进行包装,这里就不多做介绍了。
快速索引
与DotNet数据对象结合的自定义数据对象设计 (一) 数据对象与DataRow
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述