在传统的数据建模中,允许为 Null 值的外键被认为是一种不好的实践,。这并不是 Hibernate的要求.---Hibernate文档
2013年1月29日:补充:
简单地说,数据库的外键关联所描述的最严格与最精准的事物关系应该是像“子-父”这样的单向多对一关系,也即,“子”必有“父”!而反方向的一对多的关系并不是其所能准确描述,原因就是“父”未必有“子”,所以从这个角度上说,使用关联表描述单向一对多是更加贴切的。
我在Hibernate2010年的笔记中对为什么单向一对多(one-to-many)的映射要使用关联表做过讨论,但是我觉得那时候的认识并不深刻,也不太具有说服力,今天我有了进一步的思考。
首先必须明确,一对一,一对多或者多对多都是领域对象间的关系,它们体现的是业务层面上各种事物之间的对应关系。这些对应关系与数据库上的外键关联是有本质区别的。但是当我们需要持久化这些数据时,又必须要把它们之间的这些关系以数据库方式保存起来,或者说是以数据库的方式对这些关系进行模拟。很显然,可供我们使用的方式无非就是外键关联和关联表。
我们先来看外键关联:
在所有对象关系中双向一对多也就是最最典型的“父子关系”(注意,严格来说父子关系和双向一对多多对一关系是有一点差别的,那就是父子关系中要求子是一定有父的,而单向多对一中并没有明确要求一方是一定存在的,这个我在后面会再细说)使用外键关联是最贴切的!
外键关联是两张表级别上的关联关系,这里有一个暗含的要求,那就是两张表的全部记录应该都满足这种约束才对(像在父子关系中,子一定有父一样!)。虽然这不是必须的。因为一旦我们允许外键列为空就会使得一些数据可以不受此外键约束,这于我们设置外键关联的初衷就背道而驰了。从一对多的语义上来看,它只期望从单端能够找到一组多端对象,至于多端对象是不是都有一个对应的单端对象,是不再其关心或者表述范围之内的。显然,要实现这种语义,必须置多端对象的外键为可空,来放宽于约束。从数据库设计的角度来看,外键为空是一种不好的设计,而使用关联表则可以避开这个问题。我们可以看到关联表允许我们只是对两表之间的“部分”数据间的关系进行表达。它们这种关系并不是表级别的,也就是说并不是每条记录都有这种关系,这比使用允许外联列为空的外键约束要自然和合理。
由此我想,是不是对于单向多对一(many-to-one)来说,如果它对应的那个one不是必须有的时候,那我们是不是也不应该使用外键关联呢?我想答案是肯定的。
最后再简明的把这个问题描述一下:
因为单向一对多关系中对many方与one方之间的关系没有相关的描述,many方可能有对应的one方也可能没有,在这种情况下使用外键约束是不合适的。而使用关联表的好处就在于可以“规避”这个问题,也就是不正面回应这个问题。因为单向一对多关系本身就不关心这个问题。