目前来说比较.net下最好的bdb操作封装(附单元测试)
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Linq;
5 using System.Runtime.Serialization.Formatters.Binary;
6 using System.Text;
7 using BerkeleyDb;
8 using Component;
9
10 namespace ToolManager
11 {
12 public class BDBRecord
13 {
14 public object Key { get ; set ; }
15 public string Value { get ; set ; }
16 } /**/ /// <summary>
17 /// BDB数据库操作类库
18 /// </summary>
19 public class BDBHelper
20 {
21
22 private string DBFilePath { get ; set ; }
23 private DBStoreType DBType { get ; set ; }
24 public enum DBStoreType : byte
25 {
26 Auto = 1 ,
27 Queue,
28 Hash
29 }
30 [Obsolete( " 该构造函数已废弃 ,请使用BDBHelper(string dbfilePath) " )]
31 public BDBHelper()
32 {
33 }
34
35 public BDBHelper( string dbfilePath)
36 {
37 this .DBFilePath = dbfilePath;
38 }
39 [Obsolete( " 该构造函数已废弃 ,请使用BDBHelper(string dbfilePath) " )]
40 public BDBHelper( string dbfilePath, DBStoreType type)
41 {
42 this .DBFilePath = dbfilePath;
43 this .DBType = type;
44 }
45 public BDBRecord FindOne()
46 {
47 return this .FindOne( null );
48 }
49 public BDBRecord FindOne(Func < object , string , bool > predicate)
50 {
51 // Dictionary<string, object> dict = new Dictionary<string, object>();
52 try
53 {
54 Queue格式 #region Queue格式
55 // if (this.DBType == DBStoreType.Queue)
56 // {
57 using (Db db = new Db(DbCreateFlags.None))
58 {
59 db.RecLen = 5000 ;
60 db.RecPad = ' . ' ;
61 DbQueue file = (DbQueue)db.Open( null , this .DBFilePath, null , DbType.Queue, Db.OpenFlags.Create, 0 );
62 using (DbQueueCursor cursor = file.OpenCursor( null , DbFileCursor.CreateFlags.None))
63 {
64 foreach (KeyDataPair kvp in cursor)
65 {
66 BinaryFormatter bf = new BinaryFormatter();
67 MemoryStream stream = new MemoryStream();
68 stream.Write(kvp.Data.Buffer, 0 , kvp.Data.Size);
69 stream.Seek( 0 , SeekOrigin.Begin);
70 string k = BitConverter.ToInt32(kvp.Key.Buffer, 0 ).ToString();
71 object v = bf.Deserialize(stream);
72 if (predicate == null )
73 {
74 return new BDBRecord() { Key = v, Value = k } ;
75 }
76 else if (predicate(v, k))
77 {
78 return new BDBRecord() { Key = v, Value = k } ;
79 }
80 }
81 }
82 }
83 // }
84 #endregion
85 }
86 catch (Exception ex)
87 {
88 Hash格式 #region Hash格式
89 // else if(this.DBType==DBStoreType.Hash)
90 // {
91 // 遍历数据
92 using (Db db = new Db(DbCreateFlags.None))
93 {
94 // 这里如果应用Db.OpenFlags.Create则在启动后会覆盖同名文件,并新建同名文件
95 // Db.OpenFlags.Truncate会清空数据库
96 DbHash dbf = (DbHash)db.Open( null , this .DBFilePath, null , DbType.Hash,
97 Db.OpenFlags.ThreadSafe, 0 );
98
99 using (DbHashCursor cursor = dbf.OpenCursor( null , DbFileCursor.CreateFlags.None))
100 {
101 foreach (KeyDataPair kvp in cursor)
102 {
103 BinaryFormatter bf = new BinaryFormatter();
104 MemoryStream stream = new MemoryStream();
105 stream.Write(kvp.Data.Buffer, 0 , kvp.Data.Size);
106 stream.Seek( 0 , SeekOrigin.Begin);
107 string k = Encoding.UTF8.GetString(kvp.Key.Buffer, 0 , kvp.Key.Size);
108 object v = bf.Deserialize(stream);
109 if (predicate == null )
110 {
111 return new BDBRecord() { Key = v, Value = k } ;
112 }
113 else if (predicate(v, k))
114 {
115 return new BDBRecord() { Key = v, Value = k } ;
116 }
117 }
118 }
119 }
120 #endregion
121 // }
122 }
123 // return dict;
124 return null ;
125 }
126 public Dictionary < object , string > FindAll(Func < object , string , bool > predicate)
127 {
128
129 Dictionary < object , string > dict = new Dictionary < object , string > ();
130 try
131 {
132 Queue格式 #region Queue格式
133 // if (this.DBType == DBStoreType.Queue)
134 // {
135 using (Db db = new Db(DbCreateFlags.None))
136 {
137 db.RecLen = 5000 ;
138 db.RecPad = ' . ' ;
139 DbQueue file = (DbQueue)db.Open( null , this .DBFilePath, null , DbType.Queue, Db.OpenFlags.Create, 0 );
140 using (DbQueueCursor cursor = file.OpenCursor( null , DbFileCursor.CreateFlags.None))
141 {
142 foreach (KeyDataPair kvp in cursor)
143 {
144 _Do2(kvp, predicate, dict);
145 }
146 }
147 }
148 // }
149 #endregion
150 }
151 catch (Exception ex)
152 {
153 Hash格式 #region Hash格式
154 // else if(this.DBType==DBStoreType.Hash)
155 // {
156 // 遍历数据
157 using (Db db = new Db(DbCreateFlags.None))
158 {
159 // 这里如果应用Db.OpenFlags.Create则在启动后会覆盖同名文件,并新建同名文件
160 // Db.OpenFlags.Truncate会清空数据库
161 DbHash dbf = (DbHash)db.Open( null , this .DBFilePath, null , DbType.Hash,
162 Db.OpenFlags.ThreadSafe, 0 );
163
164 using (DbHashCursor cursor = dbf.OpenCursor( null , DbFileCursor.CreateFlags.None))
165 {
166 foreach (KeyDataPair kdp in cursor)
167 {
168 _Do(kdp, predicate, dict);
169 }
170 }
171 }
172 #endregion
173 // }
174 }
175 return dict;
176 }
177 public Dictionary < object , string > FindAll()
178 {
179 // either below works fine
180 // return this.FindAll((s, o) => true);
181 return this .FindAll( null );
182 }
183 private static void _Do(KeyDataPair kvp, Func < object , string , bool > predicate, Dictionary < object , string > result)
184 {
185 BinaryFormatter bf = new BinaryFormatter();
186 MemoryStream stream = new MemoryStream();
187 stream.Write(kvp.Data.Buffer, 0 , kvp.Data.Size);
188 stream.Seek( 0 , SeekOrigin.Begin);
189 string k = Encoding.UTF8.GetString(kvp.Key.Buffer, 0 , kvp.Key.Size);
190 object v = bf.Deserialize(stream);
191 if (predicate == null )
192 {
193 result.Add(v, k);
194 }
195 else if (predicate(v, k))
196 {
197 result.Add(v, k);
198 }
199 }
200 private static void _Do2(KeyDataPair kvp, Func < object , string , bool > predicate, Dictionary < object , string > result)
201 {
202 BinaryFormatter bf = new BinaryFormatter();
203 MemoryStream stream = new MemoryStream();
204 stream.Write(kvp.Data.Buffer, 0 , kvp.Data.Size);
205 stream.Seek( 0 , SeekOrigin.Begin);
206 string k = BitConverter.ToInt32(kvp.Key.Buffer, 0 ).ToString();
207 object v = bf.Deserialize(stream);
208 if (predicate == null )
209 {
210 result.Add(v, k);
211 }
212 else if (predicate(v, k))
213 {
214 result.Add(v, k);
215 }
216 }
217 /**/ /// <summary>
218 /// 更新数据库中的数据
219 /// </summary>
220 /// <param name="predicate"> execute condition </param>
221 /// <param name="isMatchOnlyOnce"> is match only once </param>
222 /// <returns> effect records </returns>
223 public int UpdateInQueueMode(Func < int , object , bool > predicate, object value, bool isMatchOnlyOnce)
224 {
225 int count = 0 ;
226 if (predicate == null )
227 return 0 ;
228 // 遍历数据
229 using (Db db = new Db(DbCreateFlags.None))
230 {
231 db.RecLen = 5000 ;
232 db.RecPad = ' . ' ;
233 // 这里如果应用Db.OpenFlags.Create则在启动后会覆盖同名文件,并新建同名文件
234 // Db.OpenFlags.Truncate会清空数据库
235 DbQueue dbf = (DbQueue)db.Open( null , this .DBFilePath, null , DbType.Queue,
236 Db.OpenFlags.ThreadSafe | Db.OpenFlags.Create, 0 );
237
238 using (DbQueueCursor cursor = dbf.OpenCursor( null , DbFileCursor.CreateFlags.None))
239 {
240 BinaryFormatter bf = new BinaryFormatter();
241 MemoryStream stream = new MemoryStream();
242 foreach (KeyDataPair kdp in cursor)
243 {
244 int k = BitConverter.ToInt32(kdp.Key.Buffer, 0 );
245 Console.WriteLine( " k={0} " , k.ToString());
246 stream.SetLength( 0 );
247 stream.Position = 0 ;
248 stream.Write(kdp.Data.Buffer, 0 , kdp.Data.Size);
249 stream.Seek( 0 , SeekOrigin.Begin);
250 object v = bf.Deserialize(stream);
251 if (predicate(k,v))
252 {
253 count ++ ;
254 // string d = Encoding.UTF8.GetString(kdp.Data.Buffer, 0, kdp.Data.Size);
255 // 如何读取Queue类型的主键值
256
257
258 // Console.WriteLine("{0},{1}", p2.State, p2.Os);
259 // p2.Os = "changed";
260 // stream = new MemoryStream();
261 stream.Position = 0 ;
262 stream.SetLength( 0 );
263 bf.Serialize(stream, value);
264 DbEntry data = DbEntry.InOut(stream.ToArray());
265 cursor.Put( ref data);
266 if (isMatchOnlyOnce)
267 {
268 stream.Close();
269 return count;
270 }
271 }
272 }
273 stream.Close();
274 }
275 }
276 return count;
277 }
278
279 public void CreateInQueueMode( object value)
280 {
281 Db PC = new Db(DbCreateFlags.None);
282 PC.RecLen = 5000 ;
283 PC.RecPad = ' . ' ;
284 DbQueue file = (DbQueue)PC.Open( null , this .DBFilePath, null , DbType.Queue, Db.OpenFlags.Create | Db.OpenFlags.ThreadSafe, 0 );
285 // CreateSecondaryDB(file,"Id.PCs.s",new DbFile.KeyGeneratorFcn(Common.Id));
286 // CreateSecondaryDB(file, "Id.PCs.s", new DbFile.KeyGeneratorFcn(Common.Id));
287 // 由于数据量不是很大,不考虑使用二级数据库,直接使用游标操作,降低复杂度
288 // 首先遍历数据库看有没有已经存在,如果没有,则添加一个,如果有,改变其状态
289 BinaryFormatter bf = new BinaryFormatter();
290 MemoryStream stream = new MemoryStream();
291 bf.Serialize(stream, value);
292 DbEntry k = DbEntry.Out( new byte [ 1024 ]);
293 DbEntry data = DbEntry.InOut(stream.ToArray());
294 file.Append( null , ref k, ref data);
295 stream.Close();
296 file.Sync();
297 PC.Close();
298 }
299 public int DeleteInQueueMode(Func < int , object , bool > predicate, bool isMatchOnlyOnce)
300 {
301 int count = 0 ;
302 if (predicate == null )
303 return 0 ;
304 // 遍历数据
305 using (Db db = new Db(DbCreateFlags.None))
306 {
307 db.RecLen = 5000 ;
308 db.RecPad = ' . ' ;
309 // 这里如果应用Db.OpenFlags.Create则在启动后会覆盖同名文件,并新建同名文件
310 // Db.OpenFlags.Truncate会清空数据库
311 DbQueue dbf = (DbQueue)db.Open( null , this .DBFilePath, null , DbType.Queue,
312 Db.OpenFlags.ThreadSafe | Db.OpenFlags.Create, 0 );
313
314 using (DbQueueCursor cursor = dbf.OpenCursor( null , DbFileCursor.CreateFlags.None))
315 {
316 BinaryFormatter bf = new BinaryFormatter();
317 MemoryStream stream = new MemoryStream();
318 foreach (KeyDataPair kdp in cursor)
319 {
320 int k = BitConverter.ToInt32(kdp.Key.Buffer, 0 );
321 Console.WriteLine( " k={0} " , k.ToString());
322 stream.SetLength( 0 );
323 stream.Position = 0 ;
324 stream.Write(kdp.Data.Buffer, 0 , kdp.Data.Size);
325 stream.Seek( 0 , SeekOrigin.Begin);
326 object v = bf.Deserialize(stream);
327 if (predicate(k, v))
328 {
329 count ++ ;
330 // string d = Encoding.UTF8.GetString(kdp.Data.Buffer, 0, kdp.Data.Size);
331 // 如何读取Queue类型的主键值
332
333
334 // Console.WriteLine("{0},{1}", p2.State, p2.Os);
335 // p2.Os = "changed";
336 // stream = new MemoryStream();
337 // stream.Position = 0;
338 // stream.SetLength(0);
339 // bf.Serialize(stream, v);
340 // DbEntry data = DbEntry.InOut(stream.ToArray());
341 // cursor.Put(ref data);
342 cursor.Delete();
343 if (isMatchOnlyOnce)
344 {
345 stream.Close();
346 return count;
347 }
348 }
349 } stream.Close();
350 }
351 }
352 return count;
353 }
354
355 /**/ /// <summary>
356 /// 用于向支持重复键值的数据库文件添加数据
357 /// </summary>
358 /// <param name="key"></param>
359 /// <param name="value"></param>
360 public void CreateInHashModeWithDup( string key, object value)
361 {
362 // 这里只是更新了一条记录,更新多条同key的情况没有考虑
363 Db db = new Db(DbCreateFlags.None);
364 db.SetFlags(DbFlags.Dup);
365 DbFile dbf = db.Open( null , this .DBFilePath, null , DbType.Hash, Db.OpenFlags.Create | Db.OpenFlags.ThreadSafe, 0 );
366 MemoryStream stream = new MemoryStream();
367 BinaryFormatter formatter = new BinaryFormatter();
368 formatter.Serialize(stream, value);
369 DbEntry _key = DbEntry.InOut(Encoding.UTF8.GetBytes(key));
370 DbEntry _data = DbEntry.InOut(stream.ToArray());
371 if (dbf.Put( null , ref _key, ref _data) != 0 )
372 Console.Write( " {0}:输入错误 " , key);
373 stream.Close();
374 dbf.Sync(); // 数据更新
375 db.Close();
376 }
377 /**/ /// <summary>
378 /// 默认方式,如果已有键则进行更新操作
379 /// </summary>
380 /// <param name="key"></param>
381 /// <param name="value"></param>
382 public void CreateOrUpdateInHashModeWithoutDup( string key, object value)
383 {
384 // 这里只是更新了一条记录,更新多条同key的情况没有考虑
385 Db db = new Db(DbCreateFlags.None);
386 // db.SetFlags(DbFlags.Dup);
387 DbFile dbf = db.Open( null , this .DBFilePath, null , DbType.Hash, Db.OpenFlags.Create | Db.OpenFlags.ThreadSafe, 0 );
388 MemoryStream stream = new MemoryStream();
389 BinaryFormatter formatter = new BinaryFormatter();
390 formatter.Serialize(stream, value);
391 DbEntry _key = DbEntry.InOut(Encoding.UTF8.GetBytes(key));
392 DbEntry _data = DbEntry.InOut(stream.ToArray());
393 if (dbf.Put( null , ref _key, ref _data) != 0 )
394 Console.Write( " {0}:输入错误 " , key);
395 stream.Close();
396 dbf.Sync(); // 数据更新
397 db.Close();
398 }
399 public int UpdateInHashMode(Func < string , object , bool > predicate, object value, bool isMatchOnlyOnce)
400 {
401 int count = 0 ;
402 if (predicate == null )
403 return count;
404 // 遍历数据
405 using (Db db = new Db(DbCreateFlags.None))
406 {
407 // 这里如果应用Db.OpenFlags.Create则在启动后会覆盖同名文件,并新建同名文件
408 // Db.OpenFlags.Truncate会清空数据库
409 DbHash dbf = (DbHash)db.Open( null , this .DBFilePath, null , DbType.Hash,
410 Db.OpenFlags.ThreadSafe | Db.OpenFlags.Create, 0 );
411
412 using (DbHashCursor cursor = dbf.OpenCursor( null , DbFileCursor.CreateFlags.None))
413 {
414 BinaryFormatter bf = new BinaryFormatter();
415 MemoryStream stream = new MemoryStream();
416 foreach (KeyDataPair kvp in cursor)
417 {
418 stream.SetLength( 0 );
419 stream.Position = 0 ;
420 stream.Write(kvp.Data.Buffer, 0 , kvp.Data.Size);
421 stream.Seek( 0 , SeekOrigin.Begin);
422 string k = Encoding.UTF8.GetString(kvp.Key.Buffer, 0 , kvp.Key.Size);
423 object v = bf.Deserialize(stream);
424 if (predicate(k, v))
425 {
426 count ++ ;
427 stream.SetLength( 0 );
428 stream.Position = 0 ;
429 bf.Serialize(stream, value);
430 DbEntry data = DbEntry.InOut(stream.ToArray());
431 cursor.Put( ref data, DbKeyCursor < DbHashCursor, DbHash > .PutMode.Current);
432 if (isMatchOnlyOnce)
433 {
434 stream.Close();
435 return count;
436 }
437 }
438 }
439 stream.Close();
440 }
441 }
442 return count;
443 }
444 public int DeleteInHashMode(Func < string , object , bool > predicate, bool isMatchOnlyOnce)
445 {
446 int count = 0 ;
447 if (predicate == null )
448 return count;
449 // 遍历数据
450 using (Db db = new Db(DbCreateFlags.None))
451 {
452 // 这里如果应用Db.OpenFlags.Create则在启动后会覆盖同名文件,并新建同名文件
453 // Db.OpenFlags.Truncate会清空数据库
454 DbHash dbf = (DbHash)db.Open( null , this .DBFilePath, null , DbType.Hash,
455 Db.OpenFlags.ThreadSafe | Db.OpenFlags.Create, 0 );
456
457 using (DbHashCursor cursor = dbf.OpenCursor( null , DbFileCursor.CreateFlags.None))
458 {
459 BinaryFormatter bf = new BinaryFormatter();
460 MemoryStream stream = new MemoryStream();
461 foreach (KeyDataPair kvp in cursor)
462 {
463 stream.SetLength( 0 );
464 stream.Position = 0 ;
465 stream.Write(kvp.Data.Buffer, 0 , kvp.Data.Size);
466 stream.Seek( 0 , SeekOrigin.Begin);
467 string k = Encoding.UTF8.GetString(kvp.Key.Buffer, 0 , kvp.Key.Size);
468 object v = bf.Deserialize(stream);
469 if (predicate(k, v))
470 {
471 count ++ ;
472 cursor.Delete();
473 if (isMatchOnlyOnce)
474 {
475 stream.Close();
476 return count;
477 }
478 }
479 }
480 stream.Close();
481 }
482 }
483 return count;
484 }
485 }
486 }
487
unit test code
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using Component;
6 using MbUnit.Framework;
7
8 namespace ToolManager.Test
9 {
10 [TestFixture]
11 class BDBHelperTest2
12 {
13 hash mode unit test #region hash mode unit test
14 [Row( " 1 " )]
15 [Row( " 2 " )]
16 [Row( " 1 " )]
17 [RowTest]
18 public void CreateInHashModeWithDupTest( string key)
19 {
20 BDBHelper bdb = new BDBHelper( " zzzzzzzzzzzzzzzzzzz.p " ,BDBHelper.DBStoreType.Auto);
21 UrlConfig config = new UrlConfig()
22 {
23 Url = " zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz " ,
24 CreatedOn = DateTime.Now
25 } ;
26 bdb.CreateInHashModeWithDup(key,config);
27 }
28 // [Row("2")]
29 // [Row("1")]
30 [Row( " 2 " )]
31 [Row( " 3 " )]
32 [RowTest]
33 public void CreateOrUpdateInHashModeWithoutDup( string key)
34 {
35 BDBHelper bdb = new BDBHelper( " 222222222.p " , BDBHelper.DBStoreType.Auto);
36 UrlConfig config = new UrlConfig()
37 {
38 Url = " ccccccccccc " ,
39 CreatedOn = DateTime.Now
40 } ;
41 bdb.CreateOrUpdateInHashModeWithoutDup(key, config);
42 }
43 [Test]
44 public void UpdateInHashModeTest()
45 {
46 UrlConfig config = new UrlConfig()
47 {
48 Url = " dddddddeeeeee " ,
49 CreatedOn = DateTime.Now
50 } ;
51 BDBHelper bdb = new BDBHelper( " 222222222.p " , BDBHelper.DBStoreType.Auto);
52 int actual = bdb.UpdateInHashMode((a, b) => (b as UrlConfig).Url.Equals( " ccccccccccc " ), config, false );
53 Assert.AreEqual( 2 ,actual);
54 }
55 [Test]
56 public void DeleteInHashModeTest()
57 {
58 UrlConfig config = new UrlConfig()
59 {
60 Url = " dddddddeeeeee " ,
61 CreatedOn = DateTime.Now
62 } ;
63 BDBHelper bdb = new BDBHelper( " 222222222.p " , BDBHelper.DBStoreType.Auto);
64 int actual = bdb.DeleteInHashMode((a, b) => (b as UrlConfig).Url.Equals( " ccccccccccc " ), false );
65 Assert.AreEqual( 2 ,actual);
66 }
67
68 #endregion
69
70 queue mode unit test #region queue mode unit test
71 [RepeatTest( 5 )]
72 public void CreateInQueueModeTest()
73 {
74 UrlConfig config = new UrlConfig()
75 {
76 Url = " www.bjut.edu.cn " ,
77 ModifiedOn = DateTime.Now
78 } ;
79 BDBHelper bdb = new BDBHelper( " CreateInQueueModeTest.p " , BDBHelper.DBStoreType.Auto);
80 bdb.CreateInQueueMode(config);
81 }
82 [Test]
83 public void UpdateInQueueModeTest()
84 {
85 UrlConfig config = new UrlConfig()
86 {
87 Url = " www.maolz.com " ,
88 ModifiedOn = DateTime.Now
89 } ;
90 BDBHelper bdb = new BDBHelper( " CreateInQueueModeTest.p " , BDBHelper.DBStoreType.Auto);
91 int actual = bdb.UpdateInQueueMode((a, b) => a > 10 , config, false );
92 Assert.AreEqual( 1 ,actual);
93 }
94 [Test]
95 public void DeleteInQueueModeTest()
96 {
97 BDBHelper bdb = new BDBHelper( " CreateInQueueModeTest.pddd " , BDBHelper.DBStoreType.Auto);
98 int actual = bdb.DeleteInQueueMode((a, b) => a > 8 , false );
99 Assert.AreEqual( 0 ,actual);
100 }
101
102 #endregion
103
104 }
105 }
106
查看更多关于目前来说比较.net下最好的bdb操作封装(附单元测试)的详细内容...