Java 如何防止双向关系中的循环

Java 如何防止双向关系中的循环,java,entity-relationship,foreign-key-relationship,entities,bidirectional,Java,Entity Relationship,Foreign Key Relationship,Entities,Bidirectional,假设我们有以下两个实体 库 public class Library { private Collection<Book> books = new ArrayList<Book>(); public boolean add(Book book) { return books.add(book); } public boolean remove(Book book) { return book

假设我们有以下两个实体

public class Library
{
    private Collection<Book> books = new ArrayList<Book>();

    public boolean add(Book book)
    {
        return books.add(book);
    }
    public boolean remove(Book book)
    {
        return books.remove(book);
    }
}
这是一种双向关系,很可能很快就会破裂。即使向库中添加了一本书,该书的库也不会更新。即使你更新了一本书的图书馆,图书馆也不会更新

那么,您将如何以良好的方式保持这种双向关系?当然,我可以在
setLibrary
中执行
add
+
remove
,反之亦然,但据我所知,这将导致一个循环,该循环可能以
StackOverflowError

为关系定义一个“所有者”而结束。图书馆是“拥有”这本书还是这本书拥有图书馆

这个问题的答案告诉您谁更新了“从属”实体

我觉得图书馆拥有这本书,所以“将书添加到图书馆”代码应该进入图书馆,然后更新后面的参考资料。

我是不是傻了

public boolean add(Book book)
{
   book.setLibrary(this);
   return books.add(book);
}
public boolean remove(Book book)
{
   book.setLibrary(null);
   return books.remove(book);
}

在您提出的解决方案中,您不能检查引用是否相等以避免循环吗

public boolean add(Book book)
{
   if(book.getLibrary != this) book.setLibrary(this);
   return books.add(book);
}

虽然我推荐Aaron定义关系所有者的方法,但另一种方法允许
集合
/
添加
/
删除
方法保持不变,即也定义相应的
has
方法(
库中的
hasBook
库中的
hasBook
)。在调用关系另一端的
add
remove
方法之前,首先查询它是否已经存在,如果不存在,则不调用它。

no。问题是,如果您除此之外还执行
this.books.remove(此);这本书=书;this.books.add(this)setLibrary
类中的code>。好的,那么这就是通常的做法?因此在这种情况下,
Book
可能是哑的,您只需在
Library
类中调用
setLibrary
。@Svish:是的,这就是想法,您只能将书籍添加到库中,然后设置书籍的库。不能直接在书本上设置库。是。这是一个解决办法,因为Veredesmarld的建议在今天的计算机上太慢了。如果问题“这本书已经在图书馆里了吗”的复杂性是O(1)(无论图书馆有多大,都需要相同的时间),那么我们可以负担两边的附加代码。这是有意义的。那么我想我会这样做:)那不行:如果这本书已经在另一个图书馆,书中的图书馆参考不会被更新,你最终会得到一本在几个图书馆(从图书馆的角度来看)的书,但这本书会认为它只是在其中一个图书馆。如果检查速度快,这将是一个完美的解决方案。今天的计算机仍然太慢了:(@Aaron Digulla:我同意,这就是为什么我在前面说我更喜欢你的方法,但我仍然觉得值得指出这是一个选择。是的,我会按照@Aaron的建议去做,但这也是一个很好的观点,我可能会在其他情况下使用:)
public boolean add(Book book)
{
   if(book.getLibrary != this) book.setLibrary(this);
   return books.add(book);
}