美文网首页
Vapor 2.0 - 关系(Relations)

Vapor 2.0 - 关系(Relations)

作者: 韩云智VL | 来源:发表于2017-08-10 14:18 被阅读0次

    前往 Vapor 2.0 - 文档目录

    Fluent的关系可以让你用三种不同的方式来描述你的模型:

    类型Type 关系Relations
    一对一One to One 父/子Parent / Child
    一对多One to Many 父/孩子们Parent / Children
    多对多Many to Many 兄弟姐妹Siblings

    一对多(One to Many)

    我们将从一对多开始,因为它是最简单的关系类型。

    采取以下数据库模式:
    users

    id name
    <id type> string

    pets

    id name user_id
    <id type> string <id type>

    瞧一瞧
    有关如何创建模式的更多信息,请
    访问数据库准备指南。

    这里每只宠物只有一个拥有者(一个用户),每个拥有者可以拥有多个宠物。这是一对多的关系。一位业主有很多宠物。

    提示
    使用builder.foreignId()创建外IDS一样user_id。这将自动创建外键约束并遵循预设的键命名约定。

    孩子们(Children)

    要访问用户的宠物,我们将使用该Children关系。

    extension User {
        var pets: Children<User, Pet> {
            return children()
        }
    }
    

    想象一下孩子的关系为Children<Parent, Child>Children<From, To>。这里我们从用户类型到宠物类型有关。

    我们现在可以使用这种关系来获取所有用户的宠物。

    let pets = try user.pets.all() // [Pet]
    

    这将创建类似于以下的SQL

    SELECT * FROM `pets` WHERE `user_id` = '...';
    

    关系的工作类似于查询(Query)

    let pet = try user.pets.filter("name", "Spud").first()
    

    父(Parent)

    要从宠物身上获取宠物的所有者,我们将使用该Parent关系。

    extension Pet {
        let userId: Identifier
    
        ...
    
        var owner: Parent<Pet, User> {
            return parent(id: userId)
        }
    }
    

    假设父关系为Parent<Child, Parent>Parent<From, To>。这里我们从宠物类型到父类型。

    注意
    请注意,Parent关系需要传入一个标识符。确保在模型的init(row:)方法中加载此标识符。

    我们现在可以使用这种关系来获得宠物的主人。

    let owner = try pet.owner.get() // User?
    
    迁移(Migration)

    将父标识符添加到子表可以使用.parent()模式构建器上的方法来完成。

    try database.create(Pet.self) { builder in
        ...
        builder.parent(User.self)
    }
    

    一对一(One to One)

    一对一关系与一对多关系完全一样。您可以使用前一个示例中的代码,并简单地调用.first()和来自父类型的所有调用。

    但是,您可以为此添加方便。我们假设我们想将上一个例子从一对多改为一对一。

    extension User {
       func pet() throws -> Pet? {
            return try children().first()
       } 
    }
    

    多对多(Many to Many)

    许多关系需要一个表来存储哪个模型与哪个模型相关。这个表被称为“主表”。

    你可以使用任何你想要的实体作为主元,但是Fluent提供了一个默认的主元(Pivot)。

    采取以下模式。
    pets

    id name
    <id type> string

    pet_toy

    id pet_id toy_id
    <id type> <id type> <id type>

    toys

    id name
    <id type> string

    在这里,每个宠物都可以拥有许多玩具,而且每个玩具都可以归属于许多宠物。这是多对多关系。

    兄弟姐妹(Siblings)

    为了表示这种多对多的关系,我们将使用这种Siblings关系。

    extension Pet {
        var toys: Siblings<Pet, Toy, Pivot<Pet, Toy>> {
            return siblings()
        }
    }
    

    想像兄弟姐妹的关系Siblings<From, To, Through>。在这里,我们通过pet/toy枢纽把宠物类型和玩具类型联系起来。

    注意
    一般的语法可能看起来有点吓人,但它允许一个非常强大的API。

    随着宠物的这种关系,我们可以获取一只宠物的所有玩具。

    let toys = pet.toys.all() // [Toy]
    

    兄弟姐妹的关系类似于查询(queries) 和父/子关系

    迁移(Migration)

    如果您使用的是Pivot类型,则可以将其添加到您的Droplet的准备阵列中。

    drop.preparations.append(Pivot<Pet, Toy>)
    

    如果您使用的Pivot是“直通(through)”模型,那么它还将具有从关系中添加和删除模型的方法。

    添加(Add)

    要为关系添加一个新模型,请使用.add()方法。

    try pet.toys.add(toy)
    

    注意
    新创建的中枢轴(pivot)将被返回。

    删除(Remove)

    要删除一个与之相关的模型,请使用.remove()方法。

    try pet.toys.remove(toy)
    
    附加(Is Attached)

    要检查模型是否相关,请使用.isAttached()方法。

    if try pet.toys.isAttached(to: toy) {
        // it is attached
    }
    
    自定义抛出(Custom Through)

    您可以使用任何实体类型作为您的兄弟姐妹关系中的“ through”实体。

    extension User {
        var posts: Siblings<User, Post, Comment> {
            return siblings()
        }
    }
    

    在上面的例子中,我们在评论实体上转动以检索用户已经评论过的所有帖子。

    只要“ through”实体有一个user_idpost_id,那么兄弟姐妹关系就会起作用。

    注意
    如果Comment实体不继承PivotProtocol,那么 addremoveisAttached方法将不可用。

    相关文章

      网友评论

          本文标题:Vapor 2.0 - 关系(Relations)

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