Siblings relationship between same models in Vapor

人盡茶涼 提交于 2020-04-13 17:15:40

问题


I have a User model which I want to add a friends property to. Friends, are supposed to be other Users.

I created the UserFriendsPivot:

final class UserFriendsPivot: MySQLPivot, ModifiablePivot {
    var id: Int?
    var userID: User.ID
    var friendID: User.ID

    typealias Left = User
    typealias Right = User

    static var leftIDKey: WritableKeyPath<UserFriendsPivot, Int> {
        return \.userID
    }

    static var rightIDKey: WritableKeyPath<UserFriendsPivot, Int> {
        return \.friendID
    }

    init(_ user: User, _ friend: User) throws {
        self.userID   = try user  .requireID()
        self.friendID = try friend.requireID()
    }
}

extension UserFriendsPivot: Migration {
    public static var entity: String {
        return "user_friends"
    }
}

I added the friends property to User:

var friends: Siblings<User, User, UserFriendsPivot> {
    return siblings()
}

Now, I'm seeing the following error on the line with return siblings():

Ambiguous use of 'siblings(related:through:)'

I tried to replace it with:

return siblings(related: User.self, through: UserFriendsPivot.self)

...without any luck.

I know that the two code snippets should work, because I straight-up copied them from another siblings relationship I built between Event and User that is working just fine.
The only difference I'm seeing is that I'm trying to build a relationship between the same models.

What can I do?


回答1:


Try replacing your friends definition with something like:

var friends: Siblings<User,UserFriendsPivot.Right, UserFriendsPivot> {
    return User.siblings()
}

EDIT:

It ought to work with Left and Right as the same table, but seems to fail because the aliases resolve to the base values. I.e. autocomplete in Xcode shows all the candidates for siblings all end up being of type:

Siblings<User, User, UserFriendsPivot> siblings(...)

Instead of:

Siblings<User, UserFriendsPivot.Right, UserFriendsPivot> siblings(...)

and similar.

I'd suggest raising a bug on GitHub. In the meantime, how about creating a copy of User with a different name and setting:

static let entity = "User"

to use the same physical table. Not pretty, but it might get you working.




回答2:


The issue here is that in a same-Model (User-User) siblings relation, Fluent cannot infer which sibling you are referring to – the sides need to be specified.

extension User {
    // friends of this user
    var friends: Siblings<User, User, UserFriendsPivot> {
        return siblings(UserFriendsPivot.leftIDKey, UserFriendsPivot.rightIDKey)
    }

    // users who are friends with this user
    var friendOf: Siblings<User, User, UserFriendsPivot> {
        return siblings(UserFriendsPivot.rightIDKey, UserFriendsPivot.leftIDKey)
    }
}

The other same-Model consequence is that you will not be able to use the attach convenience method to add to the pivot table, and need to manually create instead:

let pivot = try UserFriendsPivot(user, friend)
pivot.save(on: req)

(There are other approaches to work around this, I just find these straightforward ways above the easiest to use. Specifying the sides and reversing the key positions to obtain the inverse relation are the important concepts.)


as answered by grundoon



来源:https://stackoverflow.com/questions/55201301/siblings-relationship-between-same-models-in-vapor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!