Doctrine schema update always try to add NOT NULL - mysql

I have a fresh Symfony 2.8 installation, with doctrine and MySQL 5.6 stack.
After executing a doctrine:schema:update --force, i can see
Database schema updated successfully! "x" queries were executed
Here is my problem : Even if i execute it multiple time, doctrine always find schema differences.
With the --dump-sql, i can see that all of these queries are related to :
adding NOT NULL on string primary key
adding NOT NULL on datetime
field
However, when i check my database, these columns already have a NOT NULL.
Here is an example on a single property/column :
class MyEntity
{
/**
* #ORM\Id
* #ORM\Column(type="string", length=5, name="cd_key")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $code;
...
Here is the result of a SHOW CREATE TABLE my_entity; :
CREATE TABLE `my_entity` (
`cd_key` varchar(5) COLLATE utf8_unicode_ci NOT NULL,
`label` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`number` int(11) NOT NULL,
PRIMARY KEY (`cd_key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ;
And here the query doctrine try to execute with the doctrine:schema:update command :
ALTER TABLE my_entity CHANGE cd_key cd_key VARCHAR(5) NOT NULL;
I clean my Symfony cache between each command execution.
I try to add nullable=false on #Column annotation (event if it's already defined as an #Id), but no effect.
a doctrine:schema:validate don't find any mapping problem (except sync of course)
I try to drop and recreate the full database, but no effet.
Any ideas ?

This issue has been reported in 2017 at least here, here and here and supposed to be fixed by this PR.
Updating doctrine/dbal would be the solution (not working for me though):
$ composer require doctrine/dbal:^2.7.1
Unsetting the server version (mysql/mariadb) from the configuration would also fix the problem (still not for me though).
If one is using migrations he can still adjust them manually (but his schema will always be unsynced).

I've encountered a similar problem. For me deleting the table using SQL and then running again DOCTRINE:SCHEMA:UPDATE --FORCE worked for me.
It seems that doing some SQL requests manualy confuses Doctrine.
Saying that, i'm assuming you've put #ORM\Table(name="my_entity") and #ORM\Entity(repositoryClass="myrepository") over your class definition ;).
Hope it helped.

Related

Force Doctrine to create type="guid" as VARCHAR(255) instead of CHAR(36)

I am trying to add a new entity to my Symfony project that uses GUID field to map to another Entity:
// OtherEntity
/**
* #ORM\Id
* #ORM\Column(name="guid", type="guid", unique=true)
*/
protected $guid;
// New Entity
/**
* #ORM\ManyToOne(targetEntity="OtherEntity")
* #ORM\JoinColumn(name="other_guid", referencedColumnName="guid", nullable=false, onDelete="SET NULL")
*/
protected $otherEntity;
Doctrine dumps the following SQL staments to create the table for the NewEntity when using php app/console doctrine:schema:update --dump-sql:
CREATE TABLE new_entity (guid CHAR(36) NOT NULL COMMENT '(DC2Type:guid)', other_guid CHAR(36) NOT NULL COMMENT '(DC2Type:guid)', ...
ALTER TABLE new_entity ADD CONSTRAINT FK_D3D1CD16A7FC4818 FOREIGN KEY (other_guid) REFERENCES other_entity (guid) ON DELETE SET NULL;
When running doctrine:schema:update --force instead, I get the following error:
[Doctrine\DBAL\Exception\DriverException]
An exception occurred while executing 'ALTER TABLE new_entity ADD CONSTRAINT FK_D3D1CD16A7FC4818 FOREIGN KEY (other_guid) REFERENCES other_entity (guid) ON DELETE SET NULL':
SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint
After some digging I found, that type="guid"being translated to CHAR(36) is the problem. If VARCHAR(255) is used instead, everything works fine.
The problem is, that the guid field of the other_entity table is VARCHAR(255). Thus the CHAR(36) field in new_entity cannot be mapped to a field of another type.
I have recently updated my Symfony project:
doctrine/dbal v2.4.4 --> 2.5.5
doctrine/doctrine-bundle v1.2.0 --> 1.6.2
doctrine/orm v2.4.8 --> 2.5.5
symfony/symfony v2.7.7 --> v2.8.12
Running doctrine:schema:update under the old config, the GUID fields are created as VARCHAR(255) while the new config creates them as CHAR(36).
Using CHAR(36) makes sense, since this is the length of GUIDs. But the new format brings up the problem described before: Mappings to old fields of the same type (guid) are not possible any more.
I do not understand, why doctrine:schema:update does not update the existing fields to the new format as well.
Is there anything I can do do either force Doctrine to update all existing fields to CHAR(36) or to keep creating GUID as VARCHAR(255)?
Try to specify the same length for the related fields and add options={"fixed" = true}

Django BooleanField default for mysql

I am using Django 1.7 with MySQL.
I have an existing model that I want to add a BooleanField to. I want the field to default to true. Seems simple enough right? So I create my field like so:
class MyModel(models.Model):
my_field = models.BooleanField(default=True)
Then I run makemigrations and I get the following migration generated:
operations = [
migrations.AddField(
model_name='mymodel',
name='myfield',
field=models.BooleanField(default=True),
preserve_default=True,
),
]
Looks legit, however when I apply the migration the field created in my database does not have the default value, it looks like this:
my_field tinyint(1) NOT NULL,
Now, when I apply the migration existing records have the field set to 1 but what I want is for the migration to create a field that defaults to true, or 1. What am I missing here? Could anyone shed some light on what I am doing incorrectly? Any advice would be appreciated, thanks much!
Django never sets the default on a database level. If you want to support the default in legacy code, you can add a RunSQL operation to your migration that adds the default to the database column.

MySQL: Error while reverse engineering database from a sql file

I'm trying to reverse engineer a DB in MySql with a sql file generated from an OpenOffice database.
while trying to import and run the sql file, I get the following error:
ERROR: Line 1: syntax error, unexpected IDENT_QUOTED, expecting EVENT_SYM or FUNCTION_SYM. Statement skipped.
I tried many a things including removing double quotes and adding delimiter to the statements, yet the issue persists.
For your reference, please find the excerpts from the .sql file.
CREATE SCHEMA PUBLIC AUTHORIZATION DBA;
CREATE CACHED TABLE Users(UserID NUMERIC(15) NOT NULL PRIMARY KEY,FirstName VARCHAR(50),LastName VARCHAR(50),MobileNumber VARCHAR(12) NOT NULL,EmailAddress VARCHAR(50) NOT NULL,CompanyName VARCHAR(50),City VARCHAR(50),StateOrProvince VARCHAR(50),CountryOrRegion VARCHAR(50),PostalCode INTEGER,PassPhraseID NUMERIC(10) NOT NULL,Gender CHAR(1) NOT NULL,Age NUMERIC(3) NOT NULL,MaritalStatus CHAR(10),Height NUMERIC(4,1),Weight NUMERIC(3),Complexion INTEGER,PreferredMessageMode VARCHAR(10) NOT NULL,isPaid BOOLEAN NOT NULL,FBID VARCHAR(50),BBM VARCHAR(8),PreferredVerticals VARCHAR_IGNORECASE(100),EmergencyNos CHAR(60) NOT NULL,DOB DATE,PhotoID INTEGER,CategoryID NUMERIC(2) NOT NULL,isActive BOOLEAN NOT NULL,ActivationDate TIMESTAMP(0));
CREATE CACHED TABLE UserLocation(UserID NUMERIC(15) NOT NULL PRIMARY KEY,Location NUMERIC(22) NOT NULL,Timestamp TIMESTAMP(0) NOT NULL,CONSTRAINT SYS_FK_101 FOREIGN KEY(UserID) REFERENCES Users(UserID));
I have no clue about this.
Please help,
Thanks in Advance

CakePHP can't find table after creating a table

I create a table directly by a query. I only want to Import some data. Therefor i execute a query which is built dynamicly and i try execute this query in a Component-class. (I use a random existing model to execute this query is there a better why?)
$query= "CREATE TABLE IF NOT EXISTS testerdbs (
'Ü1' varchar(6) COLLATE utf8_swedish_ci DEFAULT NULL,
'Ü2' varchar(6) COLLATE utf8_swedish_ci DEFAULT NULL,
'Ü3' int(3) DEFAULT NULL,
'Ü4' varchar(6) COLLATE utf8_swedish_ci DEFAULT NULL,
'Ü5' date DEFAULT NULL
)"
$data = ClassRegistry::init('import_files');
$data->query($query);
This works fine.
In the same request i want to access the created table in the controller.
App::import('Model', "testerdb");
//$this->loadModel("testerdb");
$newTable = ClassRegistry::init("testerdb");
echo '<pre>', print_r($newTable->getColumnTypes()), '</pre>';
If I try to execute this in same request i always get the error:
Error: Table testerdbs for model testerdb was not found in datasource default.
If I do exactly the same request again, everything works fine...
I google about an hour and it seemed that cake cache the model. If I execute this request again cake cache again all the tables and than cake find my new table. So I hoped to load or import the created Table in the same request, but i don't work.
Is there another way to load the table? Where is my mistake?
Thanks for help!
This might be a bit stale, but I just spent the last week trying to work around the problem and maybe this will help someone.
The root problem is that the cache of table names is initialized before you created the temporary table, so the 'setSource' function returns an error that the temporary table does not exist.
The solution is to overrid the 'setSource' function for the Model that you are creating for 'testerdb' and remove the check on table existence (i.e. everything within the test:
if (method_exists($db, 'listSources'))' )
Your model definition should look something like this:
App::uses('AppModel', 'Model');
class testerdb extends AppModel {
public function setSource($tableName) {
$this->setDataSource($this->useDbConfig);
$db = ConnectionManager::getDataSource($this->useDbConfig);
$this->table = $this->useTable = $tableName;
$this->tableToModel[$this->table] = $this->alias;
$this->schema();
}
}
Many thanks to whomever posted the link below. This has worked with my CakePHP 2.0 instance.
http://web2.0goodies.com/blog/uncategorized/mysql-temporary-tables-and-cakephp-1-3/
Why would you only want to have a temporary table? I would just temporarily store whatever data you are importing in an in-memory model or data-structure.
If the table is not temporary, then just create it statically before you run your program.

Why can't I set the auto_increment value in my magento setup script?

I am creating a custom module with a few custom database tables. I need to set the auto_increment value to 5000 rather than having the default of 1. This can be accomplished pretty easily, but I am running into problems when trying to do it via a Magento install script. I want to know why, and how to work around the issue. Here are more details.
When I run the following create statement from a regular mysql client (like Heidi SQL, or the standard cli) the auto_increment value gets set correctly. It gets set to 5000.
CREATE TABLE mytable (
myid INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
other_column INTEGER NULL
) ENGINE=InnoDb DEFAULT CHARSET=UTF8 AUTO_INCREMENT=5000;
But when I put that exact same query into a magento install script the auto_increment is set to 1 after it runs. To be clear, the table is created as I expect, except for the fact that the auto_increment isn't set to 5000. Here is the code in the install script.
file: app/code/local/Mycompany/Mymodule/sql/mymodule_setup/mysql4-install-0.0.1.php
<?php
$installer = $this;
$installer->startSetup();
$installer->run("
CREATE TABLE {$this->getTable('mytable')} (
myid INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
other_column INTEGER NULL
) ENGINE=InnoDb DEFAULT CHARSET=UTF8 AUTO_INCREMENT=5000;
");
$installer->endSetup();
Why is this happening? Are there any workarounds?
(I'll also mention that I have tried to set the auto_increment with an ALTER statement, and I get the same problem)
You can setup your install script as an .sql file instead of .php mysql4-install-0.0.1.sql
Checkout Mage/Core/Model/Resource/Setup.php _modifyResourceDb
try {
switch ($fileType) {
case 'sql':
$sql = file_get_contents($sqlFile);
if ($sql!='') {
$result = $this->run($sql);
} else {
$result = true;
}
break;
case 'php':
$conn = $this->_conn;
$result = include($sqlFile);
break;
default:
$result = false;
}
Short answer: Script wise I don't think its possible, and using the .sql method may not work as well since it is still calling the the run(); method.
Add an auto_increment column in Magento setup script without using SQL
You can also take a look at lib/Varient/Db/Adapter/Pdo/Mysql.php for more deeper reference to whats going on in the background like, multi_query and _splitMultiQuery
Some more further reading for connection methods can be found here also:
ALTER TABLE in Magento setup script without using SQL
More than likely your going to have to go outside the realm of "The Magento Way" of doing things and after your module is installed make a custom post-install script that would run on your table and adjust the auto_increment directly.
I don't think you can set the primary key that way. All my code is built the fillowing way and it works perfectly fine:
<?php
$installer = $this;
$installer->startSetup();
$installer->run("
CREATE TABLE {$this->getTable('mytable')} (
myid INTEGER NOT NULL auto_increment,
other_column INTEGER NULL,
PRIMARY KEY (`myid`)
) ENGINE=InnoDb DEFAULT CHARSET=UTF8 AUTO_INCREMENT=5000;
");
$installer->endSetup();