分享一个Db4o的基础类,扩展你的Db4o
我在前面也给大家分享了两个Db4o的第三方库(Db4o的第三扩展库的使用),使用这些第三方库为使你写代码的效率进一步提高(当然,运行效率会怎么样得进行进一步的探讨)。前面的博客也提供了一种在不同的session中进行数据库更新的方法:DB4O在进行更新时只能在同一个session中的问题及改进方法。但在使用中会发现这种方法也有很多弊端,上博客的末尾和评论中我也做了一些讨论,当然这些讨论并不完善。
我也在尽自己的努力让大家能够更方便的使用Db4o数据库,为此,我写了一个更加实用的基础类,分享给大家:
首先我和大家分享一下我写这个类时的想法:在使用Db4o时一个非常大的不方便是如果在不同的using语句中(我习惯所有的数据库操作都用using),数据库没有办法更新,只用添加重复的数据库条目。正如DB4O在进行更新时只能在同一个session中的问题及改进方法中所说的那样,下面的代码会在数据库中添加一条数据,而不会将数据库中的内容进行更新:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
private void button4_Click(object sender, EventArgs e) { Person person; using (var db = Db4oEmbedded.OpenFile("p.db")) { person = (from Person p in db where p.Name == "TSON" select p).FirstOrDefault(); } person.Age = 27; using (var db = Db4oEmbedded.OpenFile("p.db")) { db.Store(person); } } |
所以我的想法是在每一个要加入数据库中的类中都增加一个可以唯一标志这个类的字段,在DB4O在进行更新时只能在同一个session中的问题及改进方法我尝试用了每一个数据的ID,但是数据记录在存储之前并不知道ID是多少,所以在要存储后查询ID,然后再存储,比较繁琐。次基类中使用的是GUID,既可以是唯一的,又不用多次存储。唯一的缺点是存储的数据量变大了(其实变大的量很小)。先把基类分享给大家:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 |
using DonNicky.Db.Db4o; using DonNicky.Db.Db4o.Config.Attributes; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Runtime.InteropServices; using System.Reflection; using System.Collections; namespace Riley.TSON { public class Db4objectsBase : /*IObjCloneable, */IObjCopyable { public Guid dbid = System.Guid.NewGuid(); /// <summary> /// 复制类,将传入参数变成当前对象的一个复制品 /// </summary> /// <param name="targetObject">让此对象成为this的一个复制品</param> /// <param name="depth">仿照Db4o的更新深度参数,复制深度</param> /// <param name="dbidIncluded">是复制时是否复制dbid</param> /// <remarks>此方法通过反射来进行实例的复制,所以效率较低,在使用过程中应尽量避免大量使用。 /// 此方法和可以复制的对象有: /// 1、简单类型的属性(可读可写的属性)和成员(public)变量。 /// 2、包含ICopy接口的对象。 /// 3、List和Dictionary中的变量。</remarks> public void CopyFrom(object targetObject,int depth = int.MaxValue, bool dbidIncluded = false) { if (depth < 1) { return; } if (targetObject.GetType() != this.GetType()) { throw new ObjectTypeError(); } //if (targetObject == null) //{ // targetObject = this.Clone(depth, dbidIncluded); // return; //} //First we create an instance of this specific type. //object //We get the array of fields for the new type instance. #region Fields FieldInfo[] fields = this.GetType().GetFields(); int i = 0; foreach (FieldInfo fi in targetObject.GetType().GetFields()) { //We query if the fiels support the IObjCloneable interface. Type ICopyType = fi.FieldType.GetInterface("IObjCopyable", true); if (ICopyType != null) { //Getting the IObjCopyable interface from the object. var obj = (IObjCopyable)fi.GetValue(targetObject); var thisObj = (IObjCopyable)fi.GetValue(this); if (thisObj == null) { thisObj = Activator.CreateInstance(obj.GetType()) as IObjCopyable; } //We use the clone method to set the new value to the field. //此时的tempField就是要进行Copy的Field thisObj.CopyFrom(obj, depth - 1, dbidIncluded); fi.SetValue(this, thisObj); //fields[i].SetValue(targetObject, ICopy.Clone()); } else { //不支持IObjCloneable接口,有两种情况 //1、支持IEnumerable接口 //2、不支持IEnumerable直接设置 //Now we check if the object support the IEnumerable interface, so if it does //we need to enumerate all its items and check if they support the IObjCloneable interface. Type IEnumerableType = fi.FieldType.GetInterface("IEnumerable", true); if (IEnumerableType != null) { //注意string类型也满足此要求 if (fi.FieldType.FullName != "System.String") { //Get the IEnumerable interface from the field. IEnumerable IEnum = (IEnumerable)fi.GetValue(targetObject); //This version support the IList and the IDictionary interfaces to iterate //on collections. Type IListType = fields[i].FieldType.GetInterface("IList", true); Type IDicType = fields[i].FieldType.GetInterface("IDictionary", true); int j = 0; if (IListType != null) { //Getting the IList interface. IList list = (IList)fields[i].GetValue(this); if (IEnum != null) { foreach (object obj in IEnum) { if (list == null) { ///http://bbs.csdn.net/topics/360129652 ///以上网址symbol_bc提供了以下方法 Type itemType = typeof(List<>).MakeGenericType(obj.GetType()); list = Activator.CreateInstance(itemType) as IList; } //Checking to see if the current item support the IObjCloneable interface. ICopyType = obj.GetType().GetInterface("IObjCopyable", true); if (ICopyType != null) { //If it does support the IObjCloneable interface, we use it to set the clone of //the object in the list. if (list.Count < j + 1) { //说明list不存在第j个成员,要新建 list.Add(Activator.CreateInstance(obj.GetType())); } IObjCopyable copy = (IObjCopyable)list[j]; copy.CopyFrom(obj, depth - 1, dbidIncluded); //list[j] = clone.Clone(); } //NOTE: If the item in the list is not support the IObjCloneable interface then // in the cloned list this item will be the same item as in the original list //(as long as this type is a reference type). j++; } } fields[i].SetValue(this, list); } else if (IDicType != null) { //Getting the dictionary interface. IDictionary dic = (IDictionary)fields[i].GetValue(targetObject); j = 0; foreach (DictionaryEntry de in IEnum) { //Checking to see if the item support the IObjCloneable interface. ICopyType = de.Value.GetType().GetInterface("IObjCopyable", true); if (ICopyType != null) { IObjCopyable clone = (IObjCopyable)de.Value; var dicKey = dic[de.Key]; clone.CopyFrom(dicKey, depth - 1, dbidIncluded); //dic[de.Key] = clone.Clone(); } j++; } } } else { //如果类型为string,则设置 fields[i].SetValue(this, fi.GetValue(targetObject)); } } else { //If the field doesn't support the IObjCloneable interface then just set it. if (fields[i].Name == "dbid") { if (dbidIncluded) { fields[i].SetValue(this, fi.GetValue(targetObject)); } } else fields[i].SetValue(this, fi.GetValue(targetObject)); } } i++; } #endregion #region Properity PropertyInfo[] properities = this.GetType().GetProperties(); i = 0; foreach (PropertyInfo fi in targetObject.GetType().GetProperties()) { //We query if the fiels support the IObjCloneable interface. Type ICopyType = fi.PropertyType.GetInterface("IObjCopyable", true); if (ICopyType != null) { //Getting the IObjCopyable interface from the object. var obj = (IObjCopyable)fi.GetValue(targetObject); var thisObj = (IObjCopyable)fi.GetValue(this); if (thisObj == null) { thisObj = Activator.CreateInstance(obj.GetType()) as IObjCopyable; } //We use the clone method to set the new value to the field. //此时的tempField就是要进行Copy的Field thisObj.CopyFrom(obj, depth - 1, dbidIncluded); fi.SetValue(this, thisObj); //fields[i].SetValue(targetObject, ICopy.Clone()); } else { //不支持IObjCloneable接口,有两种情况 //1、支持IEnumerable接口 //2、不支持IEnumerable直接设置 //Now we check if the object support the IEnumerable interface, so if it does //we need to enumerate all its items and check if they support the IObjCloneable interface. Type IEnumerableType = fi.PropertyType.GetInterface("IEnumerable", true); if (IEnumerableType != null) { //注意string类型也满足此要求 if (fi.PropertyType.FullName != "System.String") { //Get the IEnumerable interface from the field. IEnumerable IEnum = (IEnumerable)fi.GetValue(targetObject); //This version support the IList and the IDictionary interfaces to iterate //on collections. Type IListType = properities[i].PropertyType.GetInterface("IList", true); Type IDicType = properities[i].PropertyType.GetInterface("IDictionary", true); int j = 0; if (IListType != null) { //Getting the IList interface. IList list = (IList)properities[i].GetValue(this); if (IEnum != null) { foreach (object obj in IEnum) { if (list == null) { ///http://bbs.csdn.net/topics/360129652 ///以上网址symbol_bc提供了以下方法 Type itemType = typeof(List<>).MakeGenericType(obj.GetType()); list = Activator.CreateInstance(itemType) as IList; } //Checking to see if the current item support the IObjCloneable interface. ICopyType = obj.GetType().GetInterface("IObjCopyable", true); if (ICopyType != null) { //If it does support the IObjCloneable interface, we use it to set the clone of //the object in the list. if (list.Count < j + 1) { //说明list不存在第j个成员,要新建 list.Add(Activator.CreateInstance(obj.GetType())); } IObjCopyable copy = (IObjCopyable)list[j]; copy.CopyFrom(obj, depth - 1, dbidIncluded); //list[j] = clone.Clone(); } //NOTE: If the item in the list is not support the IObjCloneable interface then // in the cloned list this item will be the same item as in the original list //(as long as this type is a reference type). j++; } } properities[i].SetValue(this, list); } else if (IDicType != null) { //Getting the dictionary interface. IDictionary dic = (IDictionary)properities[i].GetValue(targetObject); j = 0; foreach (DictionaryEntry de in IEnum) { //Checking to see if the item support the IObjCloneable interface. ICopyType = de.Value.GetType().GetInterface("IObjCopyable", true); if (ICopyType != null) { IObjCopyable clone = (IObjCopyable)de.Value; var dicKey = dic[de.Key]; clone.CopyFrom(dicKey, depth - 1, dbidIncluded); //dic[de.Key] = clone.Clone(); } j++; } } } else { //If the field doesn't support the IObjCloneable interface then just set it. properities[i].SetValue(this, fi.GetValue(targetObject)); } } else { //If the field doesn't support the IObjCloneable interface then just set it. properities[i].SetValue(this, fi.GetValue(targetObject)); } } i++; } #endregion if (!dbidIncluded) { (this as Db4objectsBase).dbid = Guid.NewGuid(); } //return newObject; } } [ComVisibleAttribute(true)] public interface IObjCopyable { void CopyFrom(object targetObject, int depth, bool dbidIncluded); } public class ObjectTypeError : Exception { public ObjectTypeError() : base("Object Type Is Woring!") { } } } |
代码的细节我就不多说了,给大家分享一个使用方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
Person person; using (var db = Db4oEmbedded.OpenFile("p.db")) { person = (from Person p in db where p.Name == "TSON" select p).First(); } person.Age = 27; using (var db = Db4oEmbedded.OpenFile("p.db")) { var personInDb = (from Person p in db where p.dbid == person.dbid select p).First(); personInDb.CopyFrom(person); db.Store(personInDb); } |
Person和其他的类也都没有什么特别的,但他们都继承自Db4objectsBase这个基类,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
public class Person : Db4objectsBase { //public long _id; private string _name; public string Name { get { return this._name; } set { this._name = value; } } public int Age { get; set; } public double Height { get; set; } //public string[] nickName; public List<Course2> selectedCourse; //public Dictionary<string, Course2> sc2; public ClassRoom InClassRoom; } public class Course2 : Db4objectsBase { public string Name; } public class ClassRoom : Db4objectsBase { public string RoomName; } |
最后对Db4objectsBase这个类作一个说明:
1、Db4objectsBase中的CopyFrom是使用反射的方法对类进行复制,所以效率并不是很多,在进行大量对象的复制的时候要注意。
2、现在Db4objectsBase支持所有的以Db4objectsBase为基类的类的复制,而且支持List属性和变量。下一步我会增加对数组和Dictionary属性和对象的支持。
3、此基类完全避开了对数据库引擎的操作,所以对数据库的效率不会产生影响。
最后把代码分享给大家:DB4OTest-Db4objectsBase
原创文章,文章首发于:Riley Ge (@rileyge) — Steemit
原创文章,转载请注明: 转载自TsonTec:测量解决方案提供者
本文链接地址: 分享一个Db4o的基础类,扩展你的Db4o
说点什么