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
Using .joins() overwrites local model fields with same named fields from joined table #681
Comments
Theres no way to really do this automatically because theres no way to know which columns are the same between tables. user = (
User.joins("company")
.select("company.id as company_pk", "company.city as company_city", "users.*")
.where("company.name", "Acme Corp")
.first()
) |
Thanks for this info and I do understand what you mean. My apologies for not explaining this more thoroughly as In the documentation here: This notes that in its simplest form you can populate a model like this when using the @has_many decorator User.joins('posts') when using the @belongs_to decorator in the model you get exactly the same results as I have noted above, because the columns are not prefixed in any way. this also produces the same results, even if you use a where on a column in the actual model. User().join_on('company', lambda q: (
q.where('company.name', "Acme Corp")
)) I hope this clarifies things a bit more for you and I think this issue should be reopened Thanks for your help on this |
I'll check into the joins and join on behavior inside relationships maybe its calling something different. For the points on the columns being the same i don't think there is a way to get around that. You will have to add the select clauses explicitly. I don't think we can do it because:
With that being said i will reopen so i can check the behavior of the joins and join on inside relationships |
Going to close this. I will reopen the issue once again if you provide new information but this should be solved using the same select solution i explained earlier. user = (
User.joins("company")
.select("companies.id as company_pk", "companies.city as company_city", "users.*")
.where("companies.name", "Acme Corp")
.first()
) if you are doing this in a relationship you would do a select the same way @relationship
def relation(self):
return Model.joins("relation").select("companies.id as company_pk", "companies.city as company_city", "users.*") Theres no way to do this automatically so the selects would have to be done manually. Could also probably be done as a scope if you want |
Describe the bug
Using .joins() will fill the fields of the Model with the values of the joined table where the joined table has fields with the same name.
So the returned hydrated Model then contains the fields that are unique to that Model as well as the values from the joined table where the field names are the same in both tables. eg id, created_at, updated_at
!!! THIS COULD SERIOUSLY AFFECT DATA INTEGRITY !!!
To Reproduce
Schemas:
company
user
Data:
Model query:
Output:
NOTE: the id, phone and city field values are from the 'company' table row not the 'user' as expected
Expected behavior
Expected output from the above scenario
Desktop (please complete the following information):
What database are you using?
Additional context
Looks like there are currently no tests for join scenarios like this.
Additional observations:
The above scenario will generate a query similar to this:
The result will contain a column list like this:
id, company_id, first_name, last_name, phone, city, id, name, phone, city, crested_at, updated_at
noting here that the columns have no table prefix to denote which table they are for.
Additional Research:
apparently this is a known issue with sql queries in general and has no out of the box fix.
it is highlighted very succinctly here: https://stackoverflow.com/questions/329931/sql-select-join-is-it-possible-to-prefix-all-columns-as-prefix
Wth a possible way to handle this withing the framework from the same post here: https://stackoverflow.com/a/9926134
Possible options to handle this situation:
If we are just hydrating a model (which we are in this case) then generate a query to just get the models required fields:
The text was updated successfully, but these errors were encountered: