-
Notifications
You must be signed in to change notification settings - Fork 536
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
The recursive reference because of the two-way binding #522
Comments
I'm not opposed to a flag/config piece that would disable the back referencing. I'd expect a PR for it though. JSON and friends don't have this problem because we specifically ignore the R field completely and recommend people make their own object graph if they want to serialize it out. Gob to my knowledge does not have a mechanism to ignore a field via struct tags or anything like we do for JSON/TOML/YAML etc and so this is not fixable without said PR. I would also recommend you to not use Gob. It's bad in very many ways. If you want an efficient binary serialization check out Protocol Buffers or MsgPack. As is this is working as intended and there's no specific fix we can make for Gob unless that PR is created. |
@aarondl I have the same problem with a GraphQL api and I generate converts with:https://github.com/web-ridge/gqlgen-sqlboiler So when I ask {
flowBlocks {
id
blockChoice {
id
}
# Parent
flowBlock {
id
}
block {
id
title
blockType
blockChoices {
id
title
description
slug
}
}
}
} I've got a stack overflow because func BlockToGraphQL(m *models.Block) *graphql_models.Block {
r := &graphql_models.Block{.........}
if m.R != nil && m.R.BlockChoices != nil {
r.BlockChoices = BlockChoicesToGraphQL(m.R.BlockChoices)
}
return r
} func BlockChoiceToGraphQL(m *models.BlockChoice) *graphql_models.BlockChoice {
r := &graphql_models.BlockChoice{....}
if !helper.IntIsZero(m.BlockID) {
if m.R != nil && m.R.Block != nil {
r.Block = BlockToGraphQL(m.R.Block) // Stack-overflow
} else {
r.Block = BlockWithIntID(m.BlockID)
}
}
return r
} I don't think the R should be filled unless you send and explicit Load(") func BlockChoiceToGraphQL(m *models.BlockChoice, root interface{}) *graphql_models.BlockChoice {
if m == nil {
return nil
}
r := &graphql_models.BlockChoice{.......}
if !helper.IntIsZero(m.BlockID) {
if m.R != nil && m.R.Block != nil {
rootValue, sameStructAsRoot := root.(*models.Block)
if !sameStructAsRoot || rootValue != m.R.Block {
r.Block = BlockToGraphQL(m.R.Block, m)
}
} else {
r.Block = BlockWithIntID(m.BlockID)
}
}
return r
} |
I changed some things: func alreadyConverted(roots []interface{}, check interface{}) bool {
var matched int
for _, root := range roots {
if root == check {
matched++
}
}
return matched > 2
} I know have a maximum of two times the same nested struct. if !helper.IntIsZero(m.BlockID) {
if m.R != nil && m.R.Block != nil {
if !alreadyConverted(roots, m.R.Block) {
r.Block = BlockToGraphQL(m.R.Block, append(roots, m))
}
} else {
r.Block = BlockWithIntID(m.BlockID)
}
} |
@RichardLindhout The backreferencing is problematic in many ways to be honest. We recently ran into a race condition because relationship set helpers are setting .R on the method's input parameters which is probably incorrect. In v4 I think we may stop creating .R links to mirror the databases state because it is in the end a best-effort attempt and will almost always be incorrect anyway. It's up for debate whether it's good or bad tbh. I can see the utility in some cases, and in others I can see how the repercussions of it are fairly painful. |
Maybe self-referencing is not ideal. But are you removing the whole .R thing from models? I still like the .R thing. With what would you replace it? |
@RichardLindhout I doubt that I'd remove it unless I could find a good alternative (which I think I might have in my mind). It's more likely that we'd implement controls so you have the ability to turn on and off forward/backlinking/all linking in .R for a given call to a relationship helper as a baseline starting point. |
@aarondl Hi, I would like to work on this if you are still open to a PR. |
@namco1992 I think as a bandaid fix we could add some sort of gross The issue is mostly a difference in priority. Some people want the object graph in If you were to create a PR that disabled backreferencing via context I would accept it. |
Hi @aarondl, |
@namco1992 The reason for using the context approach is to allow the feature to be turned on/off per query. It may be useful at times. I think we should be encouraging a migration to the context approach as sqlboiler already supports features like So the question to me really comes down to: Is it better to disable backreferencing completely for a generated package? Or is it better to allow it to be per-query? What do you think? |
Hi @aarondl, |
I think we should not go further than specified in the code.
So in FavoriteMovies no R.User object except when someone
Gorm does this too, this is a good solution since you can specify how far you go. |
But Load("FavoriteMovies.User") should maybe not result in an extra query but should look if their is a back-reference available and then add it. But it should not be the same pointer without the R.FavorieMovies in it. |
@namco1992 The designs actually aren't mutually exclusive. Just like |
What version of SQLBoiler are you using (
sqlboiler --version
)?3.2.0
If this happened at runtime what code produced the issue? (if not applicable leave blank)
For example, we have a user table and an account table.
Because of This Commit, when we eager load the
Accounts
, there will be a recursive reference, the user.R.Account has account.R.Users, and so on. I understand it could be useful in certain cases, but when we try to gob this object and put into the cache, the gob can't handle the recursive reference properly and ends in stack overflow error.Further information. What did you do, what did you expect?
The bidirectional binding is helpful, but it will break the serialization if you happen to serialize it with a library which doesn't handle that case (like gob).
The text was updated successfully, but these errors were encountered: