How to implement non explicit 1:1 relationship with Doctrine? - php

I have two tables, Inventory and, say, Stuff. Inventory is used to store data common to Stuff and other tables. The way the DBA envisioned this working would be with us inserting the Inventory table and then using the generated ID to insert the Stuff table.
How can I implement this scenario using Doctrine 2? I'm tempted to just add a 1:1 relationship on the model but I'm not sure I can convince the DBA to change the database.

With the workaround described here http://www.doctrine-project.org/docs/orm/2.0/en/reference/limitations-and-known-issues.html#foreign-keys-as-identifiers you should be able to get the DBAs schema working. With version 2.1 of Doctrine (or the current master) you can use the new foreign key as identifier feature to get it working.
However if you are not using Sequences of Oracle/Postgresql you need to flush operations for this (persist parent, flush, associate and persist child, flush)

Related

MySQL InnoDB foreign key between different port databases [duplicate]

I know, I know, putting two related tables on different databases isn't exactly the best design practice. But for whatever's sake, suppose that I have to do it absolutely. And I have to break up two foreign-key-related tables that were previously located in a database into two databases, that are located on two different servers, but I still want to maintain the database(s) integrity. What is the best way to do this?
Edit: I am using MySQL and Symfony
I can't think of any way to do this with standard MySQL.
You could write a plugin for MySQL Proxy, that manages referential integrity between the parent and child tables on different servers:
Intercept INSERT and UPDATE against child table. Query for matching row in parent table. Fail INSERT/UPDATE if no match found in parent table.
Intercept DELETE against parent table. Query for dependent rows in child table. Fail DELETE if any dependent rows found in child table. If the constraint is intended to support cascading behavior, do that instead of failing.
Intercept UPDATE against parent table. If the primary key value is changing as part of the update, query for dependent rows found in child table. Fail UPDATE if any dependent rows found in child table. If the constraint is intended to support cascading behavior, do that instead of failing.
Note that you'd have to keep information about the referential integrity constraints in your MySQL Proxy plugin (or write a custom config file for your plugin that records the relationships). You can't use conventional FOREIGN KEY syntax to declare such constraints across MySQL instances.
Have you considered Federated tables? These are basically links to tables which are hosted on a different databases on a different/same host.
You can create a federated table locally and use that to enforce referential integrity. However, I cannot overemphasize the fact that this approach is fraught with future gotchas and not at all recommended.

Table structure in mySQL

I'm in the early stages of creating a database using MySQL and PHP and would like some advice please. I have started to collate the data and would like to start typing it into .csv files ready to import into my tables. Before I do, I'm unsure how to layout my structured columns and tables properly.
Ok, I'll try my best to make clear what I'm trying to create. I'd have my home page structure where you have a choice of selecting a list of players by season or by an A-Z list of all-time players. Once you click on a specific player from the list of players it would show something like this for their player profile: http://stats.touch-line.com/playerdet.asp?playerid=41472&cust=2&lang=0&FromSTR=TRUE&compid=&teamid=1&H2H=
How many tables would I need to create?
A player table with playerID,playerName,playerDOB,playerBirthplace,playerPosition etc.
A team table with teamID,teamName,teamNickname,teamGround,teamFounded etc.
A season table with seasonID,playerID,teamID,playerApps,playerGoals?
Or is there a quicker, more efficient way without the need to use so many tables to link the data? Any advice would be much appreciated. Thanks in advance. ;)
How many tables do I need to create?
The short answer is: one table for each "entity" type. An entity can be defined as a person, place, thing, concept or event, which can be uniquely identified, is of interest to the business, and we can store information about.
One key to database design is data analysis (Richard Perkinson "Data Analysis: The Key to Database Design", QED c.1993)
You've identified some of the important entities in your model: player, team, season. There may be some other key entities that are missing, which may be discovered later.
The attributes of each entity need to be identified, and should be dependent on the key of the entity, and not some other key. (Every attribute should be dependent on the key, the whole key, and nothing but the key, so help me Codd.)
You also need to identify the relationships that exist between the entities. Can a player be a member of more than one team? Can a player have more than one position? If a player is traded (moves from one team to another), how will that be represented in the model?
Where we encounter "many-to-many" relationships, those are represented in a separate relationship tables. Repeating attributes also get broken into separate child tables.
It's important that you get the model right, before you start combining multiple entities into the same table. Optimization usually results in a broken model; it usually doesn't fix a model that doesn't work.
Databases are designed to handle large number of rows efficiently, when the queries are in line with the model. Databases with dozens of tables can run very efficiently, and run more efficiently than databases with fewer tables.
I'd be more concerned with getting a database design that works, than I would be concerned with optimizing a design that doesn't work.

How to store/relate user-specific data (states?) for each model

For instance, if I had a table full of folders—with site-wide values for, say, name and created—and I wanted to allow each user to store their own individual metadata about those folders (e.g. expanded = 1, or label_color = 'red'), how should I organize my database?
Here's a diagram of this example, as I'm currently going about it:
Note that this is a similar setup to a pivot table, or a has-many-through, only I'd like to store/access data from the pivot table. Is this advisable or is there a better way to accomplish this behaviour?
The reason I think this might not be the most elegant is that it complicates joins in my ORM, because I am joining the metadata when loading the folder rows, so there is a double join when I load that folder as a relation to another model. How can I avoid this?
Your way looks like the best practice. I would put a primary key on both the user_id and folder_id (those two define your unique row) in your folders_usermeta table (although setting a primary key on multiple columns isn't supported by Kohana).
#biakaveron, I would never store serialized data in my database, it's not necessary, you will lose both your semantics and your SQL power. You can find out more on this here:
http://www.slideshare.net/billkarwin/sql-antipatterns-strike-back

Doctrine 2 multi-level OneToOne Cascade

I have three Doctrine entities: Device, which has a OneToOne relationship with Device\Status, which in turn has a OneToOne relationship with Device\Status\Battery.
I have {cascade="persist"} set between the related entities, and from what I've read, that should be all that is required for Doctrine to automatically persist each of the entities without having to do anything myself in the code.
Here's what I'm having problems with:
$device = new \Entities\Device();
$device->setId(100);
$status = $device->getStatus();
$status->setIpAddress('192.168.0.1');
$battery = $status->getBattery();
$battery->setInternalLevel(60);
$em->persist($device);
$em->flush();
After executing this code, I get the following error:
Entity of type Device\Status\Battery has identity through a foreign entity
Device\Status, however this entity has no identity itself. You have to call
EntityManager#persist() on the related entity and make sure that an identifier
was generated before trying to persist 'Device\Status\Battery'. In case of
Post Insert ID Generation (such as MySQL Auto-Increment or PostgreSQL SERIAL)
this means you have to call EntityManager#flush() between both persist
operations.
My question is: what is the correct way to setup my entities to ensure that they're persisted in the correct order?
The code for the entities can be found here: https://gist.github.com/1753524
All tests have been performed using the Doctrine 2.2 sandbox.
I think #CappY is right.
The problem is in the Status entity. when you do getBattery() and create a new Battery instance, it's related to the Status instance on which you called getBattery().
Since that instance hasn't been stored in the database yet, it's id hasn't been generated (because it's annotated as #GeneratedValue). you're almost right about cascade persist. except for that it's performed in memory.
So you need to persist and flush Status entity before doing getBattery() if you want to use that entity as id in Battery. Or else you could simple add an id field for Battery :)
You have to add cascade={"persist"} to your relation mapping. The answer you selected as correct is also correct but with that solution, if anything goes wrong after the parent data is inserted, there will be no transaction rollback. You have to set autocommit=false and perform commit transaction manually. With cascade={"persist"} you dont have to. Anything goes wrong during database action, everything will be rollbacked.

Doctrine ORM: Best method of using a ticket server to generate primary ids?

I am in the process of creating a centralized ticket server for handing out unique 32bit INT ids. I have a function that can be called within my application that accepts a parameter for the entity/ table, e.g. getPrimaryKey('user'). I got the idea from Flickr via this blog post:
http://code.flickr.com/blog/2010/02/08/ticket-servers-distributed-unique-primary-keys-on-the-cheap/
We will eventually be sharding our data amongst multiple MySQL databases and I would like to get this code up and running as a proof of concept.
My question is what is the best method for using this functionality within Doctrine? Obviously, using the above ticket server, I will need to specify that none of my Doctrine models contain an auto- incrementing primary key.
Is there a Doctrine_Model method I can extend that will retrieve the primary key using my getPrimaryKey method prior to inserting a new record into the database? If not, should I be approaching this problem from another place within my application?
Ideally, I would like the ids to be generated using the above method when using Doctrine relations such as:
$user = new User():
$user->name = 'Bob';
$user->Phonenumbers[]->number = '555-5555';
$user->save();
Also, the other side of this scenario is in selecting data from a particular shard. My current thought is to maintain a master list of key ranges contained on each shard like this (ignore the small number of rows per shard):
Shard A user_id 1-1000
Shard B user_id 1001-2000
Shard C user_id 2001-3000
I can then call something like getShard($table_name, $primary_key) to get the shard and possibly switch my Doctrine connection to that particular shard. Related data for a particular user/entity will most likely reside on the same shard so I am not too worried relations spanning multiple shards. Though, it may be a possibility, so any guidance on this issue would be greatly appreciated as well.

Categories