简体   繁体   中英

Symfony2 / Doctrine2 - ManyToOne - Save inverse side

I am new to Symfony and Doctrine.

I have an entity "User" and an entity "Type". One user can have one favorite type and one type can have many users that have that specific type as favorite. So I need a Many (User) to One (Type) relationship.

I implemented it and it works fine (mostly). But there is one thing I don't understand.

If I do something like that it works:

$user = new User();
$type = new Type();

$user->setFavoriteType($type);
$em->persist($user);
$em->persist($type);
$em->flush();

The objects are generated and stored to the DB. And the favorite_type_id is correctly set. So changing the owning side works as expected .

But if I add the User to the inverse side (only) and flush the entity manager the favorite_type_id is not set.

$user = new User();
$type = new Type();

$type->getUsers()->add($user); //same with $type->addUser($user);
$em->persist($user);
$em->persist($type);
$em->flush();

Why is that? Is there a reason why it does not work from the inverse side? Do I really have to set this manually? If I manipulate the addUser method in the type entity like "$user->setFavoriteType($this)" it works. But should that not be the task of doctrine?

The documentation says

When a bidirectional association is updated, Doctrine only checks on one of both sides for these changes. This is called the owning side of the association.

So it seems to be the wanted behaviour, is that right? But why? Due to performance? Semantic reasons?

I'd be glad if someone could explain that to me or tell me what I'm doing wrong.

Check out the Doctrine documentation on cascading. . This should help you get started with what it looks like you want to do, quickly and easily, by adding cascade={"persist"} and clearing your cache (to rebuild Doctrine's metadata cache).

This comes about because fundamentally, when considering persistence, Doctrine maps PHP Entities directly to database tables. In your case, Users and Types conceptually have a Many-to-One relationship, but at a database level the relationship is represented entirely on the User table - a User has a favorite type, and so the User table has a favorite_type_id column. Although we can think of Type Entities having a list of Users for which they are the favorite, this is essentially also derived by looking at the User table, there is nothing in the Type table.

Setting up Entity Mapping in Doctrine tells Doctrine what the relationship between the Entities is, and allows Doctrine to provide you with certain convenient access methods like $type->getUsers() , but doesn't change how the underlying data is stored. If I use $user->setFavoriteType I am manipulating data for which there is a direct database correspondence, but, by default, if I call $type->addUser I am not - the main purpose of making this kind of call out-of-the-box is to keep the hydrated entities you're currently working with up-to-date in the absence of simply throwing the objects away and fetching them again from the DB.

Of course, you've seen you can customise addUser to also call setFavoriteType , or configure cascading persistence as Shon M suggests, to make the behaviour a bit more like how you might expect/want it. It may seem like a waste of time to leave that out from the start, but I suspect the Doctrine devs have consciously chosen to implement the needed functionality in the simplest possible way, while documenting it clearly and offering several easy alternatives if that's what you're after, thereby catering for everyone one way or the other. Like it or not, what data is in the DB and what data is running in PHP post-hydration are technically different things, especially in a model like Doctrine where DB activity is deferred until the developer requests it, and it makes a lot of sense to make all that as explicit as possible!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM