多态 ORM 数据库模式
我记得很久以前,当我在摆弄 Java ActiveObjects ORM 时,我遇到了它声称支持的数据库模式。
然而,通过搜索总体思路很难找到模式的名称,因此如果有人能给我这个模式的名称,以及关于使用它的“干净”的一些想法,我将非常感激。
该模式定义如下:
Table:
reference_type <enum>
reference <integer>
...
... 其中字段 reference_type
的值将确定所引用的类型(以及表)。因此:
User:
location_type <l&l, address, city, country>
location <integer>
...
...根据 location_type
字段的值,外键 location
将引用 l&l
、<代码>地址、城市
或国家
表。
I remember when - a long time ago - I was messing around with the Java ActiveObjects ORM, I came across a database pattern it claimed to support.
However, it is very difficult to find the pattern's name, by search for the general idea, thus I would really appreciate it if someone could give me the name of this pattern, and some thoughts on the "cleanness" of using it.
The pattern was defined as such:
Table:
reference_type <enum>
reference <integer>
...
... where the value of the field reference_type
would determine the type (and thus the table) to which was being referred. Thus:
User:
location_type <l&l, address, city, country>
location <integer>
...
... where depending on the value of the location_type
field, the foreign key location
would refer to either the l&l
, address
, city
or country
table.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您很难找到它,因为它不是真正的(在广泛采用和鼓励的意义上)数据库设计模式。
远离这样的模式。虽然 ORM 使将数据库表映射到类型变得更容易,但表不是类型,反之亦然。虽然不清楚您所描述的模型应该做什么,但您不应该将列用作多个表的假外键(当我说“假”时,我的意思是您正在存储一个简单的标识符值对应于另一个表的主键,但您实际上无法将该列定义为外键)。
对数据库进行建模以表示数据,对对象进行建模以表示流程,并使用 ORM 和中间层进行转换;不要尝试将数据库推送到您的代码中,也不要将您的代码推送到数据库中。
编辑回复评论
您正在混合数据库和面向对象的术语;虽然我不熟悉您用来定义该函数的语法,但我假设它是
User
类型上名为getLocation
的实例函数,不带任何参数并返回一个Location
对象。数据库不支持实例(或任何基于类型的)函数的概念;关系数据库可以具有用户定义的函数,但这些是简单的过程函数,它们接受参数并返回值或结果集。除了您可以在函数体内使用它们这一事实之外,它们不以任何方式对应于特定的表或字段。话虽这么说,这里有两个问题需要回答:如何执行您所要求的操作,以及什么可能是更好的解决方案。
对于您所问的问题,听起来您有一个超类型-子类型关系,这是一种标准的数据库设计模式。在本例中,您有一个表示父级的超类型表:(
请注意,为了简单起见,我使用
LocationID
;您应该具有更具体和逻辑的属性来定义主键,如果可能的话)那么您有一个或多个定义子类型的表:
如果
Location
的特定实例只能是子类型之一,那么您应该向父表添加一个鉴别器值(Location
>Location),指示它对应的子类型。您可以使用 CHECK 约束来确保给定行的该字段中只有有效值。但最终,听起来混合方法可能会更好。从我看来,您基本上代表了两种不同类型的位置:
鉴于此,一个简单的模型将如下所示:
现在剩下的唯一问题是我们有可为空的列。如果您想让查询保持简单,但受到人们对保留可为空列的批评(合理!),那么您可以保持原样。如果您想要使用大多数人认为设计更好的数据库,您可以将两个可为空的列迁移到 6NF。这样做还会产生一个很好的副作用,让我们可以更好地控制这些字段的填充方式,而无需执行任何额外操作。
我们的两个可为 null 的字段是
City
和Address
。我假设没有City
的Address
是无意义的。在本例中,我们从LocationPostal
表中删除这两个属性,并创建另外两个表:You're having difficulty finding it because it's not a real (in the sense of widely adopted and encouraged) database design pattern.
Stay away from patterns like this. While ORM's make mapping database tables to types easier, tables are not types, and vice versa. While it's not clear what the model you've described is supposed to do, you should not have columns that serve as fake foreign keys to multiple tables (when I say "fake", I mean that you're storing a simple identifier value that corresponds to the primary key of another table, but you can't actually define the column as a foreign key).
Model your database to represent the data, model your objects to represent the process, and use your ORM and intermediate layers to do the translation; don't try to push the database into your code, and don't push your code into the database.
Edit in reponse to comment
You're mixing database and OO terminology; while I'm not familiar with the syntax you're using to define that function, I'm assuming it's an instance function on the
User
type calledgetLocation
that takes no parameters and returns aLocation
object. Databases don't support the concepts of instance (or any type-based) functions; relational databases can have user-defined functions, but these are simple procedural functions that take parameters and return either values or result sets. They do not correspond to particular tables or field in any way, other than the fact that you can use them within the body of the function.That being said, there are two questions to answer here: how to do what you've asked, and what might be a better solution.
For what you've asked, it sounds like you have a supertype-subtype relationship, which is a standard database design pattern. In this case, you have a single supertype table that represents the parent:
(Note here that I'm using
LocationID
for the sake of simplicity; you should have more specific and logical attributes to define the primary key, if possible)Then you have one or more tables that define subtypes:
If a specific instance of
Location
can only be one of the subtypes, then you should add a discriminator value to the parent table (Location
) that indicates which of the subtypes it corresponds to. You can useCHECK
constraints to ensure that only valid values are in this field for a given row.In the end, though, it sounds like you might be better served with a hybrid approach. You're fundamentally representing two different types of locations, from what I can see:
Given this, a simple model would look like this:
Now the only problem that remains is that we have nullable columns. If you want to keep your queries simple but take (justified!) flak from people about leaving nullable columns, then you can leave it as-is. If you want to go to what most people would consider a better-designed database, you can move to 6NF for our two nullable columns. Doing this will also have the nice side-effect of giving us a little more control over how these fields are populated without having to do anything extra.
Our two nullable fields are
City
andAddress
. I am going to assume that having anAddress
without aCity
would be nonsense. In this case, we remove these two attributes from theLocationPostal
table and create two more tables:在我看来,城市和国家将成为
地址
表的一部分,并且L&L不会与地址相互排斥(你可能两者都有......),所以,为什么要限制自己像这样对待一个或另一个?此外,这会阻止
location
列强制执行引用完整性,不是吗,因为它并不总是引用同一个表?Seems to me that city and country would be part of the
address
table, and that L&L wouldn't be mutually exclusive with address (you might have both...), so, why limit yourself like that to one or the other?Further more, this would prevent the
location
column from enforcing referential integrity, would it not, since it wouldn't always reference the same table?