【问题标题】:Polymorphic ORM database pattern多态ORM数据库模式
【发布时间】:2011-03-21 16:48:41
【问题描述】:

我记得很久以前 - 我在搞乱 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&amp;laddresscitycountry 表。

【问题讨论】:

    标签: database design-patterns database-design orm relational-database


    【解决方案1】:

    您很难找到它,因为它不是真正的(在被广泛采用和鼓励的意义上)数据库设计模式。

    远离这样的模式。虽然 ORM 使将数据库表映射到类型更容易,但表不是类型,反之亦然。虽然尚不清楚您描述的模型应该做什么,但您不应该将列用作多个表的假外键(当我说“假”时,我的意思是您正在存储一个简单的标识符值对应另一个表的主键,但实际上不能将该列定义为外键)。

    为您的数据库建模以表示数据,为您的对象建模以表示流程,并使用您的 ORM 和中间层进行转换;不要尝试将数据库推送到您的代码中,也不要尝试将您的代码推送到数据库中。

    根据评论进行编辑

    您正在混合使用数据库和 OO 术语;虽然我不熟悉您用于定义该函数的语法,但我假设它是 User 类型上的一个实例函数,称为 getLocation,它不接受任何参数并返回一个 Location 对象。数据库不支持实例(或任何基于类型)函数的概念;关系数据库可以具有用户定义的函数,但这些是简单的过程函数,它们接受参数并返回值或结果集。除了您可以在函数体中使用它们之外,它们不以任何方式对应于特定的表或字段。

    话虽如此,这里有两个问题需要回答:如何按照您的要求做,以及什么可能是更好的解决方案。

    对于您所问的,听起来您有一种超类型-子类型关系,这一种标准的数据库设计模式。在这种情况下,您有一个表示父级的超类型表:

    Location
    ---------------
    LocationID (PK)
    ...other common attributes
    

    (请注意,为了简单起见,我在这里使用LocationID;如果可能的话,您应该有更具体和合乎逻辑的属性来定义主键)

    那么你有一个或多个定义子类型的表:

    Address
    -----------
    LocationID (PK, FK to Location)
    ...address-specific attributes
    
    Country
    -----------
    LocationID (PK, FK to Location)
    ...country-specific attributes
    

    如果Location 的特定实例只能是其中一个子类型,那么您应该向父表 (Location) 添加一个鉴别器值,指示它对应于哪个子类型。您可以使用CHECK 约束来确保给定行的此字段中只有有效值。

    不过,最后,听起来您可能会更好地使用混合方法。从我所见,您基本上代表了两种不同类型的位置:

    • 基于坐标的位置 (L&L)
    • 基于市政/邮政/等的位置(国家/地区、城市、地址),其中每一个都只是前一个的更具体的版本

    鉴于此,一个简单的模型将如下所示:

    Location
    ------------
    LocationID (PK)
    LocationType (non-nullable) ('C' for coordinate, 'P' for postal)
    
    LocationCoordinate
    ------------------
    LocationID (PK; FK to Location)
    Latitude (non-nullable)
    Longitude (non-nullable)
    
    LocationPostal
    ------------------
    LocationID (PK, FK to Location)
    Country (non-nullable)
    City (nullable)
    Address (nullable)
    

    现在唯一剩下的问题是我们有可以为空的列。如果你想让你的查询保持简单,但从人们那里得到(有道理的!)关于保留可空列的批评,那么你可以保持原样。如果您想使用大多数人认为设计更好的数据库,您可以将我们的两个可空列移至 6NF。这样做还有一个很好的副作用,就是让我们可以更好地控制这些字段的填充方式,而无需做任何额外的事情。

    我们的两个可空字段是CityAddress。我将假设没有CityAddress 是无稽之谈。在这种情况下,我们从LocationPostal 表中删除这两个属性并创建另外两个表:

    LocationPostalCity
    ------------------
    LocationID (PK; FK to LocationPostal)
    City (non-nullable)
    
    LocationPostalCityAddress
    -------------------------
    LocationID (PK; FK to LocationPostalCity)
    Address (non-nullable)
    

    【讨论】:

    • 您对如何在数据库中对属性User#location: Location 建模有一些技巧吗? - 假设L&amp;LAddressCityCountry实现Location接口?
    • 谢谢! (不过,我在这里看到的是元组 LocationID, LocationType 非常接近我最初提出的模式,不是吗?)
    • @Pepijn:我不这么认为;我阅读您的原始帖子的方式是 Location 表将有一个包含多个表之一的键值的列,但在此模型中 Location 不引用任何表(子类型引用 @ 987654346@)。换句话说,您发布的模型似乎与它的关系相反。
    【解决方案2】:

    在我看来,城市和国家/地区将成为address 表的一部分,并且 L&L 不会与地址相互排斥(您可能同时拥有...),所以,为什么要将自己限制为一个还是其他?

    此外,这会阻止location 列强制引用完整性,不是吗,因为它不会总是引用同一个表?

    【讨论】:

      猜你喜欢
      • 2011-10-01
      • 2011-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多