Closed wundii closed 1 year ago
Hey wundii,
that is an interesting issue. I think you ran into a structural problem in Propel here.
In general, it is desired behavior that Propel gives you the same object for the same row. You do not want different objects representing the same row in the database, because then a change to the first object is not reflected in the other object, meaning that if you change the first object and save it, then save object 2, the changes you made through object 1 will be overridden (it is a bit more complicated in Propel due to change detection, but you get the idea). This is not desirable. Disabling instance pooling or cloning objects is almost guaranteed to give you the weirdest anomalies somewhere down the line.
I think the "correctish" behavior of withColumn()
would be to return an array in your case. Seems to me the result of these statements should be the same:
$authorCollection1 = AuthorQuery::create()
->filterById(2949)
->joinWithBook() // <-------- join whole table
->find();
var_export($authorCollection1->count()); // 1
var_export($authorCollection1[0]->getBooks()->getColumnValues('Id')); // [3554, 3555]
$authorCollection2 = AuthorQuery::create()
->filterById(2949)
->joinBook()->withColumn('Book.Id', 'BookIdsOnly') // <------------- join column of table
->find();
var_export($authorCollection2->count()); // 2 <------ debatable
var_export($authorCollection2[0]->getVirtualColumn('BookIdsOnly')); // 3555 <----------- not 3554, issue of ticket, but I think should be [3554, 3555],
var_export($authorCollection2[1]->getVirtualColumn('BookIdsOnly')); // 3555
Throwing an exception that withColumn()
does not work with a one-to-many relation would also be a valuable change.
On a side note, this here makes sense considering above, but without context, it is somewhat confusing:
$authorCollection3 = AuthorQuery::create()
->useBookQuery()
->filterByAuthorId(2949)
->endUse()
->find();
var_export($authorCollection3->count()); // 2
var_export($authorCollection3[0]->getBooks()->getColumnValues('Id')); // [3554, 3555],
var_export($authorCollection3[1]->getBooks()->getColumnValues('Id')); // [3554, 3555],
Not sure if it makes sens that a Query object can return more than one object for a row in the table. Results with duplicates are usually not usable.
tl;dr I think cloning the result is not a good idea, changing withColumn()
to return an array is better, but just throwing an exception would also be a valuable change. What do you think?
Merging #1836 (dd54040) into master (a9b02ae) will decrease coverage by
20.84%
. The diff coverage is75.00%
.
@@ Coverage Diff @@
## master #1836 +/- ##
=============================================
- Coverage 87.69% 66.85% -20.85%
- Complexity 7759 7760 +1
=============================================
Files 282 282
Lines 21315 21232 -83
=============================================
- Hits 18693 14195 -4498
- Misses 2622 7037 +4415
Flag | Coverage Δ | |
---|---|---|
5-max | 66.85% <75.00%> (-20.85%) |
:arrow_down: |
7.4 | 66.85% <75.00%> (-20.85%) |
:arrow_down: |
agnostic | 66.85% <75.00%> (+<0.01%) |
:arrow_up: |
mysql | ? |
|
pgsql | ? |
|
sqlite | ? |
Flags with carried forward coverage won't be shown. Click here to find out more.
Impacted Files | Coverage Δ | |
---|---|---|
src/Propel/Runtime/Formatter/ObjectFormatter.php | 68.49% <75.00%> (-22.42%) |
:arrow_down: |
src/Propel/Runtime/ActiveQuery/PropelQuery.php | 0.00% <0.00%> (-100.00%) |
:arrow_down: |
.../Propel/Generator/Command/templates/propel.yml.php | 0.00% <0.00%> (-100.00%) |
:arrow_down: |
.../Propel/Generator/Command/templates/schema.xml.php | 0.00% <0.00%> (-100.00%) |
:arrow_down: |
...el/Generator/Command/templates/propel.yml.dist.php | 0.00% <0.00%> (-100.00%) |
:arrow_down: |
...el/Runtime/Validator/Constraints/DateValidator.php | 0.00% <0.00%> (-100.00%) |
:arrow_down: |
...Generator/Manager/templates/migration_template.php | 0.00% <0.00%> (-100.00%) |
:arrow_down: |
...nerator/Builder/Om/TableMapLoaderScriptBuilder.php | 0.00% <0.00%> (-100.00%) |
:arrow_down: |
...ator/Builder/Om/templates/tableMapLoaderScript.php | 0.00% <0.00%> (-100.00%) |
:arrow_down: |
...tor/Behavior/Validate/templates/objectValidate.php | 0.00% <0.00%> (-100.00%) |
:arrow_down: |
... and 140 more |
Continue to review full report at Codecov.
Legend - Click here to learn more
Δ = absolute <relative> (impact)
,ø = not affected
,? = missing data
Powered by Codecov. Last update a9b02ae...dd54040. Read the comment docs.
I also think that this is a structural problem at Propel. :( To solve this problem, one would have to make major changes, which may not make sense at the moment.
In my current example, the primary idea is a pure readout via Propel for AgGrid and I can live with the deactivation of InstancePooling in this case. In general, I would say that almost all queries with Propel and withColumn are intended for pure reading. From this point of view, I would put an exception in there. This raises the question of where this should best be built in.
I have written an idea in the ObjectFormatter.
Shall we close this then?
At this point, problems arise if there is a one to n relationship to its table (tableOne -> tableN). If you build a query from tableOne and now add a withColumn(virtualColumn), all the different ones at tableN will get the same content because the same ObjectId is always fetched by the InstancePoolTrait. Since in my view the ObjectFormatter->format is only used for the find methods, a clone would be a good bug fix for one to n relationships.
user1 (baseball & football) user2 (baseball)
UserOneQuery::create()->useHobbyManyQuery()->endUse()->withColumn(HobbyManyTableMap::COL_HOBBY)->find(); result: -user1 | football -user1 | football -user2 | baseball
** Update I have found an alternative to the clone, Propel::disableInstancePooling(). I am now a little unsure which is the better approach for the problem described.