Symfony2 and Doctrine $em->persist VS $em->merge

Dizzy Bryan High picture Dizzy Bryan High · Apr 30, 2015 · Viewed 14.3k times · Source

Hi there I've got a quick question regarding Doctrine and the difference between merge() and persist()

I have a NewsBuilder class:

  • This takes a News Entity and checks to see if it exists in the database, if it does it sets the values of the entity to the data passed and returns the entity.
  • If it does not exist it creates a new News Entity sets the data and
    returns the entity

namespace FantasyPro\DataBundle\Builder;

use FantasyPro\DataBundle\Entity\News;
use FantasyPro\DataBundle\Helpers\DateHelper;

class NewsBuilder
{
    /**
     * @var DateHelper $dateHelper
     */
    private $dateHelper;

    public function __construct( DateHelper $dateHelper )
    {
        $this->dateHelper = $dateHelper;
    }

    public function buildNews( $currentNews = null, $news)
    {
        if ( ! $currentNews) { // check if we already have the news stored
            $currentNews = new News();
        }
        $currentNews->setNewsID( $news['NewsID'] );
        $currentNews->setTitle( $news['Title'] );
        $currentNews->setUpdated( $this->dateHelper->parseDate( $news['Updated'] ) );
        $currentNews->setUrl( $news['Url'] );
        $currentNews->setContent( $news['Content'] );
        $currentNews->setSource( $news['Source'] );
        $currentNews->setTermsOfUse( $news['TermsOfUse'] );
        $currentNews->setTeam( $news['Team'] );
        $currentNews->setPlayerID( $news['PlayerID'] );

        return $currentNews;
    }
}

this is used by a NewsPersister Class

This performs a check on my repo using FindByOne() passing the id of the data i am parsing.

    namespace FantasyPro\DataBundle\Persisters;

    use Doctrine\ORM\EntityManager;
    use FantasyPro\DataBundle\Builder\NewsBuilder;
    use FantasyPro\DataBundle\Entity\News;

    class NewsPersister {

        /**
         * @var EntityManager $em
         */
        private $em;
        /**
         * @var NewsBuilder $builder
         */
        private $builder;

        public function __construct( EntityManager $em, NewsBuilder $builder )
        {
            $this->em      = $em;
            $this->builder = $builder;
        }

        public function Persist($news){
            //get the news repository
            $repo = $this->em->getRepository( 'DataBundle:News' );

            // get the current news from the db
            $criteria    = array(
                'newsID' => $news['NewsID']
            );

            /**
             * @var News $currentNews
             */
            $currentNews = $repo->FindOneBy( $criteria );

            //todo: use a logger to write this data to file

            //build the news entity
            $currentNews = $this->builder->buildNews( $currentNews, $news );

            //persist the team
            $this->em->persist( $currentNews );
        }
    }

Hers my question: can drop the FindByOne() statement and simply use $em->merge() instead of $em->persist()

Am i right in thinking that the $em->merge sets the entity to either update or insert depending on whether the id exists or not? making my extra call to he repo unnecessary?

Answer

Evgeniy Kuzmin picture Evgeniy Kuzmin · May 1, 2015

no, you can't remove

The difference is what you do with entity after.

Persist takes an entity instance, adds it to persistance context and makes it managed, so all other updates will be managed by entity manager.

Merge will create new instance of entity, copies state from provided entity, and will makes new copy managed, but passed entity won't be managed, so futher changes won't be cached by entity manager

By your example: if you will change persist to merge, then it won't make any difference. So merge will do same job as persist. And usually you should use merge when you have detached entity or unserialized (i.e from cache)