How to save one Doctrine entity to two database ta

2019-09-05 18:37发布

问题:

In my database I've a table file and a table file_content. The file table stores the metadata of the file such as name, mime and some more. The file_content stores a blob with the file content. I'm not storing the blob in the same table as the metadata for performance reasons only.

For a 'version 2' of my project I'm looking into Doctrine (2.3). To me, a "File" seems to be one entity, with properties such as name, mime, extension, content that should be used like this:

$file = new File();
$file->setName('hello.txt');
$file->setMime('text/plain');
$file->setContent('Hello world!')
$em->persist($file);
$em->flush();

Is this behaviour possible? To me it makes no sense to create two entities for something that's really just one entity. I could not find anything about it in the documentation and I read in a 2-year-old topic that it isn't possible in Doctrine 2.1: Doctrine 2.1 - Map entity to multiple tables

Someone any suggestions how to handle this correctly? I'm new to Doctrine and have been playing around with it a bit to see if it's the right choice for my project. Thanks.

回答1:

Do you have the ability to alter the schema of your database? If so, I'd consider consolidating this into one table.

Barring that, you may want to try a one-to-one relationship in Doctrine. Perhaps something like:

class File {
    private $id;
    private $name;
    private $mime;
    private $content;
}

class Content {
    private $id;
    private $data;
    private $fileId;
}

If you map Content->fileId with a one-to-one relationship to File->id, then you can do things like:

$file->getContent()->getData();
$file->getContent()->setData("something different");

Here's some more info on one-to-one mappings: http://docs.doctrine-project.org/en/2.0.x/reference/association-mapping.html#one-to-one-unidirectional



回答2:

I'm going to suggest a different approach even though it's a somewhat older question. Instead of making two entities, you should make three.

Create FileMetadata, which holds name, mimetype, etc. Create FileContent, which holds the content. Then, create a third entity File which holds a one-to-one connection with one of each of the other types, and give it a bunch of methods that simply call the matching methods on the sub entities.

So for example in File, the setName method would look like this:

  public function setName() {
    $this->getFileMetadata()->getName();
  }

And set would look like this:

  public function setName( $name ) {
    $this->getFileMetadata()->setName( $name );
  }

The constructor of the File entity should create a new FileMetadata and a new FileContent on creation and should NOT have a setFilemetadata or setFilecontent method; these two entities should be completely shielded from your application.

Now you have the File entity, which handles exactly like you want (a single entity, no additional sub-entities) which is still stored neatly in two (well, three really) different tables.



回答3:

You could map both tables, resulting in File and FileContent, and add a one-to-one relationship between the two. Then add getter/setter methods for the file content in the File class. In these you'd have to call the corresponding methods in FileContent.