如何在对象数据库中设计多对多关系?

16

我认为现在是时候研究一下面向对象数据库了,所以我决定在我的下一个小项目 - 一个小型图书馆中使用db4o。

考虑以下对象:Book(书),Category(类别)。

一本书可以属于0到n个类别,一个类别可以应用于0到m本书。

我的第一个想法是有一个连接的对象,比如BookCatecory,但是经过一些搜索之后,我发现这对于“真正的OO”来说并不合适。

因此,另一种方法(被许多人推荐)是在两个对象中都有一个列表:Book.categories 和 Category.books。其中一边处理关系:Book.addCategory将Category添加到Book.categories,并将Book添加到Category.books。当在一个方法调用中修改两个对象时,如何处理提交和回滚呢?

你有什么想法?第二种方法有明显的优势,但至少对我来说,第一种方法“感觉”正确(更好规范化)。

6个回答

10
我能想到的解决这个问题的方法只有两种,你已经提到了。个人而言,我会选择第一种方法(创建映射对象作为面向对象实体)。这可以避免保留冗余信息并进行同步;这也意味着如果关联最终拥有自己的字段(比如书籍被分配到该类别的日期),它们可以轻松地合并。我们在系统中使用此方法来处理各种关联。
面向对象实体将如下所示:
BookCategory {
 Book book
 Category category
}
Book {
 Collection <BookCategory> categories
}
Category {
 Collection <BookCategory> categories
}

在这种情况下,您需要保持关系对象和两个集合同步,但是这些集合是可选的。通常,您可以通过ORM查询获得相同的信息,类似于: select b.book from BookCategory b where b.category = MyCategory
另一种选择是设置如下:
Book {
 Collection<Category> categories
}

Category {
 Collection<Books> books
}

如果你的ORM/DB工具自动维护关联,那么这很好;否则,你就需要更新两个集合。 (在Hibernate中,映射上一个属性将为:inverse=true;这一方不会被更新,严格来说它不需要被维护。但我认为这是不好的实践。)
如果你通常只单向访问关系(例如获取类别中的所有书籍),你可以消除另一侧的集合;然后我认为你必须绕过ORM工具并使用本地查询才能从另一个方向访问关系。
我们在项目中使用Hibernate(一种基于Java的对象关系映射工具);Hibernate文档是OO/关系设计问题的良好参考,但您可能需要花费一些时间学习Hibernate才能使其有用:http://docs.jboss.org/hibernate/stable/core/reference/en/html_single/#collections-ofvalues 希望对你有所帮助!

我应该提一下,我不熟悉db40;这个答案通常适用于您所描述的ORM问题,希望能有所帮助 =) - RMorrisey

4
如果您使用对象数据库,就不需要关心关系在数据库中是如何存储的。您只需要定义类和它们之间的关系即可。请参考您所使用的数据库的文档。以下是一些关系的示例:
n:n attribute, referencing from the parent
------------------------------------------------------------------
class Person {
    List addresses;
}

class Address {
}


n:n attribute, referencing from the child
------------------------------------------------------------------
class Person {
}

class Address {
    List persons
}

n:n attribute, bidirectional references
------------------------------------------------------------------
class Person {
    List addresses;
}

class Address {
    List persons
}

1

我认为你可能有点固守关系型数据库的思维方式。在每个对象中使用列表是正确的面向对象编程方法。提交和回滚不是问题,它们发生在一个事务中,可以提交所有更改或回滚所有更改。


1
在纯面向对象数据库(如GemStone)中,对象本身具有对其他对象的引用集合。当应用程序引用对象时,OODBMS会生成一个包装对象的代理。其模式仅为持久化对象及其引用的对象集合。OODBMS不一定需要链接实体。
使用O/R映射层(假设它足够聪明以处理M:M关系),M:M关系表现为对象本身上的子参考集合,O/R映射器将其解析为幕后的链接实体。并非所有O/R映射器都这样做,因此您可能需要单独的链接对象。

1

你有使用ODBMS的特定原因吗?对于简单的数据结构(例如对书籍进行分类),你通常不会发现ODBMS比RDBMS更具优势,事实上,在RDBMS的标准化世界中工作会更容易。当你使用复杂的数据类型或动态对象的文字持久性/存储时,ODBMS具有非常明显的优势。ODBMS也被认为比RDBMS更快,更可扩展,但我自己无法提供太多见解。以下是一些讨论RDBMS与ODBMS的页面:

面向对象数据库到底怎么了

面向对象数据库与面向对象关系数据库(SO)


我想看看是否可以避免创建dbschema、创建表、创建对象、将表映射到对象等等。似乎odbms可以减少很多繁琐的工作... - paul
它可能会减少一些工作量,但一个不错的ORM层也可以做到同样的效果。我并不是说ODBMS是错误的选择,但有其他替代方案可能会更好地为您服务。 - Thom Smith

0

我会避免数据重复,因为这样会导致合并差异时出现各种问题。

关键在于引用。

结果是,我会让每个对象包含对另一种对象类型的引用集合,并且还有一个独立的其他对象集合。

匹配表是一个关系概念,除非中间连接类可能具有不可归属于任何一个对象的属性。它存在的原因是使查询能够以强大的方式编写,因为它将关系减少为两个一对多关系,并大大减少了数据重复。如果在关系数据库中没有匹配表进行操作,那么事情很快就会变得非常糟糕——更新操作该如何进行?个人认为面向对象数据库的吸引力在于远离这种情况。

我将所有对象绑定在一起的方法是通过代码中的事件到某种事务处理程序,以允许缓存对象状态。因此,对象不是相互操作属性,而是通过处理程序请求更改,并在回调中等待结果。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接