前段时间写了那篇关于Db4o 主键问题的文章,应用时发现Guid类型的主键在数据删除后仍然留在数据文件中。
分析发现Guid类型属于引用类型,Db4o将其当成实体对象保存了,然而在逻辑意义上我们并不认为Guid是以个实体数据。
解决方法自然是有的,Db4o未删除Guid类型的ID,是因为未设置级联删除,在数据库开启前(必须是开启前设置)为类别设置级联删除即可,计提方式请参考相应文档。
但是,Db4o在级联操作上的局限性就在于,只能对一个类别设置级联属性,而不能对单个属性设置(至少我现在没有发现相应的方法可以为单个属性设置级联属性)。这样的话仅仅为了一个ID就对该类设置级联删除是很不明智的,简单考虑一下文章与文章类别的例子就很容易发现了,我要删除文章的ID,就不得不删除文章所属的分类。。。
不用级联删除还可以通过Db4o的事件特性来实现,具体点就是在数据的删除事件中删除他的ID。但是Guid值作为一个逻辑值类型,在数据库中是不止一份的(这个很难讲的明白,就像1 2 3 4这样的值类型,实际上Db4o在存储操作时,完全是把引用类型当值类型用的),当你删除的时候你实际上删除的不是某一个ID,而是数据库中所有的这个Guid。相当于关系型数据库中,我删除了父表中的一项,却没把子表中的引用项设空一样。破坏了数据完整性。
所以最终解决方案是使用一个值类型的id(自动生成可以用Date.Now的滴答数来代替),这就不存在实体类被删除,ID还存在的情况。
同样通过这一现象,我发现Db4o里面使用引用类型的字段是很不安全的,很容易造成数据库垃圾堆积(有点像C里面的内存泄露)。举个例子Subject为文章类型,Article为文章,很自然的我们会如下定义这两个类(.NET3.5):
class Article{
public string Title{get;set;}
public Subject Subject;
}
class Subject{
public string Name;
}
模拟一个基本流程:添加分类->添加文章->修改文章分类->删除文章
首先添加分类会在数据库中创建一条关于分类的记录
添加文章中的Subject属性在保存前会设定一个数据库中存在的分类,但是此处在保存文章时,又会产生一个相同的分类条目(感觉Db4o的Store方法设计有问题)
修改文章分类的时候文章原来的分类是一个被复制的分类,再设置的时候又会有一条分类被复制,甚至于你仅仅修改文章的标题都会有一条分类条目被复制。
不知道Db4o里面对这些“孤岛数据”有没有垃圾回收机制,数据库毕竟与面向对象环境不同,如果这些“孤岛数据”一直存在的话,数据库的急速增长是不可避免的(网上对此问题的抱怨也是有的)。
Db4o的思想很先进,确实给开发工作带来很大便利,可能在实现上还有一定问题,技术尚不成熟(虽然版本已经达到7.X了),所以建议在使用Db4o技术建模时,尽量避免引用类型的使用(string类型除外),特别是一对多关系,尽量用ID代替实际引用。如果不可避免的要用引用类型,要么设置级联删除,要么设置删除事件,要么就干脆使用“特性标记”使该字段不可被序列化
Db4o真的没想象中那么简单。
关于Db4o的使用,后续还会有文章介绍
分析发现Guid类型属于引用类型,Db4o将其当成实体对象保存了,然而在逻辑意义上我们并不认为Guid是以个实体数据。
解决方法自然是有的,Db4o未删除Guid类型的ID,是因为未设置级联删除,在数据库开启前(必须是开启前设置)为类别设置级联删除即可,计提方式请参考相应文档。
但是,Db4o在级联操作上的局限性就在于,只能对一个类别设置级联属性,而不能对单个属性设置(至少我现在没有发现相应的方法可以为单个属性设置级联属性)。这样的话仅仅为了一个ID就对该类设置级联删除是很不明智的,简单考虑一下文章与文章类别的例子就很容易发现了,我要删除文章的ID,就不得不删除文章所属的分类。。。
不用级联删除还可以通过Db4o的事件特性来实现,具体点就是在数据的删除事件中删除他的ID。但是Guid值作为一个逻辑值类型,在数据库中是不止一份的(这个很难讲的明白,就像1 2 3 4这样的值类型,实际上Db4o在存储操作时,完全是把引用类型当值类型用的),当你删除的时候你实际上删除的不是某一个ID,而是数据库中所有的这个Guid。相当于关系型数据库中,我删除了父表中的一项,却没把子表中的引用项设空一样。破坏了数据完整性。
所以最终解决方案是使用一个值类型的id(自动生成可以用Date.Now的滴答数来代替),这就不存在实体类被删除,ID还存在的情况。
同样通过这一现象,我发现Db4o里面使用引用类型的字段是很不安全的,很容易造成数据库垃圾堆积(有点像C里面的内存泄露)。举个例子Subject为文章类型,Article为文章,很自然的我们会如下定义这两个类(.NET3.5):
class Article{
public string Title{get;set;}
public Subject Subject;
}
class Subject{
public string Name;
}
模拟一个基本流程:添加分类->添加文章->修改文章分类->删除文章
首先添加分类会在数据库中创建一条关于分类的记录
添加文章中的Subject属性在保存前会设定一个数据库中存在的分类,但是此处在保存文章时,又会产生一个相同的分类条目(感觉Db4o的Store方法设计有问题)
修改文章分类的时候文章原来的分类是一个被复制的分类,再设置的时候又会有一条分类被复制,甚至于你仅仅修改文章的标题都会有一条分类条目被复制。
不知道Db4o里面对这些“孤岛数据”有没有垃圾回收机制,数据库毕竟与面向对象环境不同,如果这些“孤岛数据”一直存在的话,数据库的急速增长是不可避免的(网上对此问题的抱怨也是有的)。
Db4o的思想很先进,确实给开发工作带来很大便利,可能在实现上还有一定问题,技术尚不成熟(虽然版本已经达到7.X了),所以建议在使用Db4o技术建模时,尽量避免引用类型的使用(string类型除外),特别是一对多关系,尽量用ID代替实际引用。如果不可避免的要用引用类型,要么设置级联删除,要么设置删除事件,要么就干脆使用“特性标记”使该字段不可被序列化
Db4o真的没想象中那么简单。
关于Db4o的使用,后续还会有文章介绍

C#泛型类的静态构造函数
关于在.NET2.0 空

