Open AlexHowansky opened 3 years ago
OK I think I found the problem. Doctrine\ORM\Mapping\DefaultQuoteStrategy::getJoinTableName()
only works if the schema name and the table name are specified separately:
@ORM\JoinTable(name="COURSE_STUDENT_JOIN", schema="APP")
While Doctrine\DBAL\Platforms\SqlitePlatform
allows the schema name to be specified as part of the table name, via dot notation:
@ORM\JoinTable(name="APP.COURSE_STUDENT_JOIN")
It seems perhaps the intent was to allow changing the dot to two underscores after the full schema+table string had been built. Can dots be disallowed in table names based on the currently selected driver? I.e., disallowing dots in SQLite table names would force use of the explicit schema syntax, which avoids this issue.
Many databases provide schema namespacing that can be used to segregate tables. The schema name can be prepended to the tablename with a namespace separator, typically a dot. For example, if you created the
USERS
table in theAPP
schema namespace, your select might look likeSELECT APP.USERS.ID FROM APP.USERS
.Doctrine recognizes this dot notation for databases like Oracle that support schema namespaces. However, since SQLite does not, Doctrine translates
APP.USERS
toAPP__USERS
to provide a sort of faux namespacing. This feature works correctly when using migrations to create the table and when using Doctrine to query it, but is broken when inserting via a ManyToMany relationship.If all the following are true:
Then the table name of the join table is not translated to
SCHEMA__TABLE
as expected, and the insert fails because it will incorrectly refer toSCHEMA.TABLE
.For example, if we define a SQLite database in our
.env
file:DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db"
And create Student and Course entities like:
Then we can run migrations to create the database and we'll get the fake namespaced table names as expected:
We can successfully use the entities to create new rows:
And to query them:
However, we'll get an error if we create a relationship that would result in an insert to the join table:
Note in the query that Doctrine built above,
APP.COURSE
has been correctly translated intoAPP__COURSE
, butAPP.COURSE_STUDENT_JOIN
has not. This occurs only for inserts into ManyToMany join tables -- inserts into other tables and read queries on the join tables (e.g.,$jim->getCourses()
) will be correctly translated.The above code can be made to work by either removing the schema namespaces from the Entity metadata definitions or changing the database driver to something that supports schema namespaces. Thus, there is a simple workaround when using a single database platform. However, applying this workaround makes the entities no longer transportable or agnostic, and prevents me (for example) from using Oracle for production and SQLite for test.
I've got a minimal repo here to demonstrate: https://github.com/AlexHowansky/doctrine_sqlite_bug
See the
src/Command/TestCommand.php
file for an example containing the code noted here.doctrine:common 3.1.0 doctrine:dbal 2.12.1 doctrine:orm 2.8.1