05.实体关系

作者: gthank | 来源:发表于2020-05-09 16:07 被阅读0次

    05.实体关系

    实体之间可以相互关联,两个实体之间的关系是由两个属性来定义的,这两个属性指定了关系的两端:

    class Customer(db.Entity):
        orders = Set('Order')
    
    class Order(db.Entity):
        customer = Required(Customer)
    

    在上面的例子中,我们有两个关系属性:orderscustomer,当我们定义实体Customer时,实体Order还没有定义,这就是为什么我们要在订单属性中的订单周围加上引号。

    另一种方法是使用lambda:

    class Customer(db.Entity):
        orders = Set(lambda: Order)
    

    如果你想让你的IDE检查声明的实体名称并高亮显示错别字,这可能很有用。

    一些映射器 (例如 Django) 只要求在一侧定义关系,Pony 要求在两边显式地定义关系 (正如《Python之禅》中所说:显式比隐式更好),这使得用户可以从每个实体的角度看所有的关系。

    所有的关系都是双向的。如果你更新了一个关系的一边,另一边也会自动更新。例如,如果我们创建了一个订单实体Order的实例,客户的订单集将被更新至包含这个新订单。

    关系有三种类型:一对一、一对多和多对多关系。一对一的关系很少使用,大多数实体之间的关系是一对多和多对多的关系。

    如果两个实体之间有一对一的关系,那往往意味着它们可以组合成一个实体。

    如果你的数据图有很多一对一的关系,那么这可能是你需要重新考虑实体定义的信号。

    个人意见:这个需要根据实际需求来定,如果一个表很宽(字段很多),这时候可以根据业务及使用频率,考虑将其拆分为多个表——gthank

    一对多的关系

    下面是一个单对多关系的例子:

    class Order(db.Entity):
        items = Set("OrderItem")
    
    class OrderItem(db.Entity):
        order = Required(Order)
    

    在上面的例子中,没有订单,OrderItem的实例就不能存在。如果我们想让OrderItem的实例不被分配给一个订单而存在,我们可以将订单属性定义为Optional:

    class Order(db.Entity):
        items = Set("OrderItem")
    
    class OrderItem(db.Entity):
        order = Optional(Order)
    

    多对多的关系

    为了创建多对多关系,你需要将关系的两端定义为Set属性。

    class Product(db.Entity):
        tags = Set("Tag")
    
    class Tag(db.Entity):
        products = Set(Product)
    

    为了在数据库中实现这种关系,Pony将创建一个中间表。这是一个众所周知的解决方案,可以让你在关系型数据库中拥有多对多关系。

    一对一关系

    为了创建一对一的关系,应该将关系属性定义为Optional-RequiredOptional-Optional

    class Person(db.Entity):
        passport = Optional("Passport")
    
    class Passport(db.Entity):
        person = Required("Person")
    

    不允许将这两个属性定义为必填,因为这样做没有意义。

    自我引用

    一个实体可以使用自我参照关系与自身建立关系。这种关系可以分为两种类型:对称关系和非对称关系。

    非对称关系是由属于同一实体的两个属性定义的。

    对称关系的具体情况是,实体只指定了一个关系属性,而这个属性定义了关系的双方。这种关系可以是一对一的关系,也可以是多对多的关系。下面是自引用关系的例子。

    class Person(db.Entity):
        name = Required(str)
        spouse = Optional("Person", reverse="spouse") # 对称的一对一
        friends = Set("Person", reverse="friends")    # 对称的多对多
        manager = Optional("Person", reverse="employees") # 非对称的一面
        employees = Set("Person", reverse="manager") # 非对称的另一面
    

    两个实体之间的多重关系

    当两个实体之间有一个以上的关系时,Pony需要指定反向属性,这样做的目的是为了让Pony知道哪一对属性之间有关系。

    让我们考虑一下这个数据图,在这个数据图中,用户可以写推文,也可以收藏推文:

    class User(db.Entity):
        tweets = Set("Tweet", reverse="author")
        favorites = Set("Tweet", reverse="favorited")
    
    class Tweet(db.Entity):
        author = Required(User, reverse="tweets")
        favorited = Set(User, reverse="favorites")
    

    在上面的例子中,我们必须指定反向选项。如果你试图为实体定义生成映射而不指定反向属性,你会得到异常pony.orm.core.erDiagramError: "Ambiguous reverse attribute for Tweet.author"

    之所以出现这种情况,是因为属性author在技术上可以与tweetsfavorites相关,而Pony没有任何信息说明应该使用哪个属性。

    相关文章

      网友评论

        本文标题:05.实体关系

        本文链接:https://www.haomeiwen.com/subject/ogiknhtx.html