views:

162

answers:

1

I have two objects: File and FileDetail. A File can have many FileDetails, but a FileDetail can only have one File. I can get this to work, but I can't delete anything from the database because of key constraints (I can't delete the File row because FileDetail depends on it, and vice versa). I have the following yaml:

File:
  columns:
    id:
      type: integer
      primary: true
      autoincrement: true
    ...
    fileDetail_id: integer
  relations:
    ...
    FileDetail:
      local: fileDetail_id
      foreign: id
      cascade: [delete]

FileDetail:
  columns:
    id:
      type: integer
      primary: true
      autoincrement: true
    file_id: integer
    ...
  relations:
    ...
    File:
      local: file_id
      foreign: id
      foreignAlias: Revisions
      cascade: [delete]

Ideally what I would like to happen is when I delete the File row, that all the child FileDetails are deleted as well. It would even be nice if I could just manually delete all the FileDetail rows and then the File row, but because of the key constraints I'm unable to:

1451 - Cannot delete or update a parent row: a foreign key constraint fails (`file`, CONSTRAINT `file_filedetail_id_file_detail_id` FOREIGN KEY (`filedetail_id`) REFERENCES `file_detail` (`id`))

How would I get this type of relationship to work (One-To-Many on one side, but One-To-One on the other). Or should I just treat this as a Many-To-Many on both sides?

+3  A: 

With Doctrine, it can often be better to only define the relationship on one side (usually the owning side) and let Doctrine work out the rest. Here, you've got a cascading deletion which looks to be going both ways. Try altering your schema to:

File:
  columns:
    id:
      type: integer
      primary: true
      autoincrement: true
    ...
  relations:
    ...
    Revisions:
      class: FileDetail
      local: id
      foreign: file_id
      type: many
      cascade: [delete]

FileDetail:
  columns:
    id:
      type: integer
      primary: true
      autoincrement: true
    file_id: integer

and leave the cascade on the File side only. That way, when you delete a File, its associated FileDetail records will be deleted as well. I've also changed the alias to Revisions as per your original schema, so you'll be able to do:

$file->Revisions->{some FileDetail field here}

which I think is what you were after. I've removed the filedetail_id field from your File record as if you can have many FileDetail records per file, your File record would not be able to store all the IDs of those records in a single integer field.

And finally, I've added type: many to the owning side, so Doctrine knows that it's a one-to-many relationship from the File side.

richsage
+1 on that. Taught him everything I know. Only took an hour...
johnwards