Doctrine many-to-many relationship wants to create a table twice when I create a migration - doctrine

Before I describe my problem, it might actually make it clearer if I start with the error I'm getting:
$ ./app/console doc:mig:diff
[Doctrine\DBAL\Schema\SchemaException]
The table with name 'user_media_area' already exists.
That's absolutely true - user_media_area does exist. I created it in a previous migration and I don't understand why Symfony is trying to create the table again.
My problem has something to do with a many-to-many relationship. I have a table called user, a table called media_area and a table called user_media_area.
Here's the code where I tell user about media_area (Entity/User.php):
/**
* #ORM\ManyToMany(targetEntity="MediaArea", inversedBy="mediaAreas")
* #JoinTable(name="user_media_area",
* joinColumns={#JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#JoinColumn(name="media_area_id", referencedColumnName="id")}
* )
*/
private $mediaAreas;
And here's where I tell media_area about user (Entity/MediaArea.php):
/**
* #ORM\ManyToMany(targetEntity="User", mappedBy="users")
*/
private $users;
What's interesting is that if I remove that JoinTable stuff from Entity/User.php, ./app/console doctrine:migrations:diff will work again:
/**
* #ORM\ManyToMany(targetEntity="MediaArea", inversedBy="mediaAreas")
*/
private $mediaAreas;
However, it's a little off: it now wants to create a new table called mediaarea, which I don't want. My table already exists and it's called media_area.
So it looks like either way, Symfony is trying to create a table based on this ManyToMany thing in my User class, and the only reason the problem goes away when I remove the JoinTable is that the name of the table it wants to create (mediaarea) no longer matches the actual name of my table (media_area).
So my question is: Why does it want to create a new table at all? What am I doing wrong?
(I know it's possible that my naming conventions are off. Symfony and Doctrine's database examples are frustratingly devoid of multi-term column names, so I don't always know if I'm supposed to do media_area or mediaArea.)

According to the Association Mapping explanation on the official docs, the #JoinColumn and #JoinTable definitions are usually optional and have sensible default values, being:
name: "<fieldname>_id"
referencedColumnName: "id"
From that we can conclude that there is really no concrete difference between the two implementations you presented.
However, when it comes to migration, the creation of the table is a pretty common and expected behaviour. The thing is the table should always get deleted and created again, which is not happenning.
About the table name issue, the default behaviour of Doctrine 2 about this:
/**
* #ORM\ManyToMany(targetEntity="MediaArea", inversedBy="mediaAreas")
*/
private $mediaAreas;
Is to try and create a table called mediaarea. Again, perfectly normal.
If you want to declare a specific name for the table of an entity, you should do this:
/**
* #ORM\Table(name="my_table")
*/
class Something
I'm not sure if that helps you at all, but I guess it puts you, at least, on the right track.

Related

IBM DB2 + Doctrine - Auto increment in composite primary keys

My problem is easy to understand and many mentioned here in Stackoverflow with references to Doctrine docs.
Every entity with a composite key cannot use an id generator other
than "ASSIGNED". That means the ID fields have to have their values
assigned before you call EntityManager#persist($entity).
I tried this, getting last generated ID, adding + 1 to its value and persisting entity. The problem is that a third party software that uses the same IBM DB2 database, cannot add a row, because the auto increment index is not updated when I insert a row in that way.
Is there a way to make this work or a way to update the table auto increment index?
Thanks in advance.
EDIT
In order to help you to better understand what I want/have to achieve, I will show you my example.
EntityClass
class Entity
{
/**
* #ORM\Id
* #ORM\Column(type="string", name="serie")
*/
protected $serie;
/**
* #ORM\Id
* #ORM\Column(type="integer", name="reference")
* #ORM\GeneratedValue
*/
protected $reference;
// More code...
}
Multiple primary keys are allowed by doctrine, but for some reason, when I fill the entity this way
$entity = new Entity();
$entity->set("serie", date('Y')); // Custom setter that search the property and sets the value. In this case, current year as string
// More assignements, except for the autoincrement value
$em->persist($entity);
$em->flush();
It throws an exception saying that one of the ids is not filled and MUST be filled in a composite key entity, but it is an auto increment column and I need to make it work that way, find a way to get the next auto increment value for the table or update auto increment value for the table in IBM DB2. If not, the other third party software will crash if I get the max value of the auto increment column, increase that value by one and assign it to the entity manually.
The query:
SELECT presence FROM DB2ADMIN.PRESENCES WHERE serie LIKE 2017 ORDER BY presence DESC FETCH FIRST 1 ROWS ONLY;
If you need any further information, let me know.
There's two ways to do this, but since you don't have access to transactions (and apparently don't care about gaps), I don't recommend one of them.
The first way, which I'm recommending you not use, is to create a table to hold the generated value, incrementing that, and returning it. I previously answered a question about this for SQL Server, but the concept should translate. Note that some of the utility is lost since you can't generate the value in a trigger, but should still work. The primary remaining issue is that the table represents a bottleneck, which you're not getting much benefit out of.
The second way is just to use a separate SEQUENCE for each year. This is somewhat problematic in that you'd need to create the object each year, but would be much faster to get a number. You'd also be essentially guaranteed to have gaps.
Note that I'm always a little suspicious of primary keys where the value is incremented and has value, especially if gaps are allowed.

TYPO3 cache behaviour with updated models

I have this weird behaviour from Typo3 6.2 LTS.
In my extension I have a Model with a FileReference Property. This property has a vaule != 0. This value does exist in sys_file_reference table.
Not the weird magic happens. If I try to access this file, I do only get a nullvalue instead of a FileReference- / FileObject.
We already cleared our cache (server and browser) but nothing. It's still null.
I appreciate every kind of help!
Greetz, Paddaels
I remember it was always hard to make a 1:1 relation from a domain model to a FileReference. I suggest you to use existing patterns and work with a ObjectStorage for that purpose.
You can copy the neccessary TCA from the existing tca of the tt_content table (field image for example). The Property annotation should look like:
/**
* #var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\Vendor\Extension\Domain\Model\FileReference>
* #lazy
* #cascade remove
*/
protected $propName;
Of course you have to create the FileReference Model in your own namespace. But you can extend the Extbase basemodel, so you dont have to write any methods.
To map your model to the sys_file_reference table you have to add some typoscript.
For that purpose create a ext_typoscript_setup.txt in your extensions folder and insert the following code (adjust namespace and modelname)
config.tx_extbase.persistence.classes {
Vendor\Extension\Domain\Model\FileReference.mapping {
tableName = sys_file_reference
}
}
After clearing the caches in the install tool (and making database migrations of course) it should work.
Explanations:
#lazy: Typo3 wont fetch all references at once, only if the property is accessed.
#cascade remove: Extbase will delete all sys_file_reference records related to your domain model once the model is deleted.

Laravel5: How are Eloquent model relationships expressed in the database?

There's a missing link I fail to understand.
I use migrations to create database tables and I define the relationships there. meaning.. if I have a person table and a job table and I need a one to many relationship between the person and jobs, I'd have the job table contain a "person_id".
When I seed data or add it in my app, I do all the work of adding the records setting the *_id = values etc.
but somehow I feel Laravel has a better way of doing this.
if I define that one to many relationship with the oneToMany Laravel Eloquent suports:
in my Person model.....
public function jobs()
{
return $this->hasMany('Jobs);
}
what's done on the database level? how do I create the migration for such table? Is Laravel automagically doing the "expected" thing here? like looking for a Jobs table, and having a "person_id" there?
Yep, Laravel is doing what you guess in your last paragraph.
From the Laravel documentation for Eloquent Relationships (with the relevant paragraph in bold):
For example, a User model might have one Phone. We can define this
relation in Eloquent:
class User extends Model {
public function phone()
{
return $this->hasOne('App\Phone');
}
}
The first argument passed to the hasOne method is the name of the
related model. Once the relationship is defined, we may retrieve it
using Eloquent's dynamic properties:
$phone = User::find(1)->phone;
The SQL performed by this statement
will be as follows:
select * from users where id = 1
select * from phones where user_id = 1
Take note that Eloquent assumes the foreign key of the relationship based on the model name. In this case, Phone model is assumed to use a user_id foreign key.
Also note that you don't actually have to explicitly set the foreign key indexes in your database (just having those "foreign key" columns with the same data type as the parent key columns is enough for Laravel to accept the relationship), although you should probably have those indexes for the sake of database integrity.
There is indeed support to create foreign key relationships inside migration blueprints and it's very simple too.
Here is a simple example migration where we define a jobs table that has a user_id column that references the id column on users table.
Schema::create('jobs', function($table)
{
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users');
});
You can also use some other methods that laravel provides such as onDelete() or onUpdate
Of course to understand better the options that are available to you please read the documentation here.
Edit:
Keep in mind that Eloquent is just using fluent SQL wrapper and behind the scenes there are just raw sql queries, nothing magical is happening, fluent just makes your life a lot easier and helpers you write maintainable code.
Take a look here about the Query Builder and how it works and also, as #Martin Charchar stated , here about Eloquent and relationships.

Laravel 4 - is there a way to have a prefix for some tables, but not others?

Most of my database tables use a prefix set in the database config file, but I have several tables that are static that I use for lookups like States, Countries, etc. Is there a way to tell Laravel in the models or elesewhere that these tables do NOT use the prefix Right now my seeders and other features don't work because they assume the prefix.
I have the table names set in the models like this:
protected $table = 'states';
Of course I could either just make them use the prefix like all the other tables or create a separate database connection, but I'm wondering if there's another solution.
Thanks!
I was thinking about doing this for a project as well and I came upon this thread:
http://laravel.io/forum/03-20-2014-override-table-prefix-for-one-model
The last comment (as of right now at least) suggests setting up another db connection that uses an alternate (or no) prefix, then tell the specific models you want to use that connection.
eg
in the model:
protected $connection = 'db_no_prefix';
protected $table = 'this_table';
in db config
'connections' = > [
...
'db_no_prefix' => [
....
'prefix' => '',
],
],
There's no way Laravel (or any software in existence) would magically know which of your tables have prefixes and which ones don't if you don't define it somewhere. The place to define it is exactly where you said, in the model:
// State model
protected $table = 'states';
// Some other model
protected $table = 'pre_mytable';
If your models all clearly have their tables defined, your seeds should work perfectly.
Now, obviously if some piece of software had a list of database tables defined somewhere, it could iterate through them and determine which ones were prefixed. But this ultimately defeats the purpose since the original intention was for your software to figure out which ones were prefixed so it could know the table name to access.
Anyways, its a good practice to explicitly define your table names in the models. Someday down the road when you or someone else looks at your code, you might wonder what table a model is referring to, but if it's clearly defined then there is no way to be confused. Never try to rely on too much magic on an app if you want to understand things a year later.
I think part of the problem is in my seeders. I'm not using the Schema class to create the table, but am using it when dropping.
class CreateStatesTable extends Migration {
public function up()
{
DB::statement("
CREATE TABLE IF NOT EXISTS `".Config::get('database.connections.mysql.prefix')."_states` (
`state_id` tinyint(2) NOT NULL AUTO_INCREMENT,
`state_name` varchar(15) NOT NULL DEFAULT '',
`state_abbr` char(2) NOT NULL DEFAULT '',
PRIMARY KEY (`state_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=52 ;
");
}
public function down()
{
Schema::drop('states');
}
}
However, even if I solve this, I may still have problems in other parts of the system. Probably easier just to use the prefix and create duplicates of the tables in other apps.

Adding new columns to an Existing Doctrine Model

First of all Hats of to StackOverflow for their great service and to you guys for taking your time to answer our questions.
I am using Doctrine ORM 1.2.4 with CodeIgniter 1.7.3. I created a Site with some required tables and pumped in with datas only to realize at a later point of time that a specific table needs to have one more column.
The way i created the tables was by writing the model as php classes which extend the Doctrine_Record.
Now i am wondering if i need to just add the column in the model that requires a new column in the setTableDefinition() method and recreate that table or is there any other way that easily does this. The former method i've mentioned requires me to drop the current table along with the datas and recreate the table which i do not wish. Since doctrine seems to be a very well architect-ed database framework, i believe it is lack of my knowledge but surely should exist a way to add new columns easily.
PS: I am not trying to alter a column with relations to other tables, but just add a new column which is not related to any other table. Also i create the tables in the database using Doctrine::createTablesFromModels(); When i alter a table with a new column and run this method it shows errors.
Since you don't want to drop & recreate, use a Doctrine Migration.
The official docs here show many examples:
http://www.doctrine-project.org/projects/orm/1.2/docs/manual/migrations/en
Since you just want to add a field, look at their second code example as being the most relevant which is like this:
// migrations/2_add_column.php
class AddColumn extends Doctrine_Migration_Base
{
public function up()
{
$this->addColumn('migration_test', 'field2', 'string');
}
public function down()
{
$this->removeColumn('migration_test', 'field2');
}
}

Resources