-
Notifications
You must be signed in to change notification settings - Fork 2.5k
EntityManager#merge() and EntityManager#detach() removal
#1577
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Hello, thank you for creating this pull request. I have automatically opened an issue http://www.doctrine-project.org/jira/browse/DDC-4105 We use Jira to track the state of pull requests and the versions they got |
|
As discussed with @beberlei, this path is viable, but a few things must be provided instead:
|
|
I somehow agree we should get rid of |
|
@guilhermeblanco the idea is to move As per discussion with @beberlei yesterday, We need something safer and more specific. |
|
I find myself thinking of it as:
If the main driver is (de)-serialization, what about avoiding detachment entirely, and instead creating "clean clones"? A new Then, on the way back, do some privileged reflection-magic to overwrite managed entities with state from the un-managed ones: It may be slower and take more memory, but I think it could be saner in the long-run. |
Same thoughts here - we would need some sort of detach mechanism that safely applies detach, without breaking portions of the graph, but entirely cutting it out when there is any reference. |
|
My feeling is that avoiding accidental data-bugs is a higher priority than saving memory/CPU-cycles in the PHP runtime. Big organizations can spin up additional PHP instances, and people with high-performance data-dumping needs can probably find other ways to get the data out. If doctrine returns a copy of the subgraph for serialization, that's easier to control and should have cleaner failure-scenarios. |
Agree 100% - that's why we'd need a "serializer", rather than a |
|
Doctrine could also avoid the "S-word" and assume that (de)-serialization is a problem to be solved by some other library depending on how/where the user wants to transfer or archive the data. Doctrine doesn't need to care what happens to the plain old PHP objects: /*
* Get subgraph from the "root" object
*/
$plainEntity = $entityManager->cloneUnmanaged($managedEntity);
/*
* Who knows what happens to $plainEntity here? Is it (de)-serialized?
* We don't really care as long as it isn't horribly disfigured.
*/
$plainEntity = SomeSerializerRoundtrip($plainEntity)
/*
* Try to load/overwrite state represented by subgraph, throwing
* exceptions if things don't line up exactly.
*/
$entityManager->overwriteState($plainEntity);
/*
* Alternate version, where we also assert that the data coming in
* needs to be applicable to a specific managed entity or reference:
*/
$entityManager->overwriteState($plainEntity, $managedEntityOrRef); |
|
Hi, I'm currently using a lot of So I try the import from external API some entities, in order to keep my data synchronized. I totally agree that doctrine doesn't fit for that type of operation and a raw SQL requests will be awfully much faster. But I have not enough time to manage this kind of operation, and as my script took less than 10 minutes make me happy. In order to do this I need to manage my memory usage and the only way to do this I :
|
Since this operation would cause queries anyway: wouldn't it be simply safer to just re-fetch the objects? |
|
@Ocramius Not really. I made a bundle dedicated to import data from any source such as API, Excel ... The aim of my bundle is to add new source as much simple as possible ! In order to do this, I create a factory which is composed by one builder by entity that I can import. I tried to be flexible as much as possible, so I needed to handle of the complexity in my builders. The developer need to provider a parser which provide sequentially (by a function |
@Ocramius I wonder if the identity-map could optionally use weak-references... I'm not sure if the extension exists for PHP7, but I really wish that they were built-in. |
That would open a completely different can of worms about how to keep transaction integrity. Code like following would just break in a very unexpected way: $em->transactional(function ($em) use ($userIds) {
array_walk(
$userIds,
function ($userId) {
$user = $em->find(User::class, $userId);
$user->ban();
}
)
});I suggest looking at #5550 instead (for this sort of operation) |
|
I don't think serialization or partial detachment of subgraphs is really within the scope of what the ORM should do. I think within reason we can look at what needs to be possible with the ORM to enable those sorts of use cases, but IMO they're special cases that should be implemented in userland code. |
|
@zeroedin-bill I definitely agree in terms of serialization and "detach-subgraph". Do you think "copy-subgraph" would be a reasonable replacement? On the other side--with data flowing in--what about a "merge" like: /*
* Try to load/overwrite state represented by subgraph, throwing
* exceptions if things don't line up exactly. Fails if any entities
* in the subgraph do not have a @MergeMethod
*/
$entityManager->overwriteState($plainEntity);And the ORM could require that any affected entities must designate a merging-method (e.g. /*
* @Entity
*/
class Foo{
/** @Id @Column(type="integer") @GeneratedValue */
protected $id = null;
/** @Column(type="string") */
protected $a = "hello";
/** @Column(type="string") */
protected $b = "world";
/** @OneToMany(targetEntity="Bar", inversedBy="foo") */
protected $bars;
public function __construct(){
$this->bars = new ArrayCollection();
}
/*
* @MergeMethod
*/
public function myMergeMethod(Foo $other){
// Can we assume framework already checked that IDs match?
$this->a = $other->a;
$this->b = $other->b;
// Not sure if there are any gotchas in terms of lazy-proxies here
$this->bars = new ArrayCollection($other->bars->toArray());
}
}
// Class Bar omittedAlternate configuration mechanisms could be used for a static merge-method like |
|
If an entity object is kept immutable and changes for a data row has to be handled in a new object, can this change also be handled without a |
Immutability is not handled by the ORM: only one instance of an entity per identifier is allowed in a single |
…tics, which were dropped
3828baa to
34612dd
Compare
EntityManager#merge() and EntityManager#detach() removal
…ns in cascades in tests
…rations in newer metadata driver implementations
…instead Ref: doctrine#1577 (comment) - @lcobucci's review
…ntics, which were dropped
…e() and detach() semantics removal
…doctrine/common is required to completely remove those methods from the `ObjectManager` interface first
…rs are discouraged from storing entities in sessions
…cessing docs, adding links to existing batch processing utilities
…aced by clear() documentation only
…ns in cascades in tests
…rations in newer metadata driver implementations
…instead Ref: doctrine#1577 (comment) - @lcobucci's review
This PR simply attempts to get rid of
EntityManager#merge()andEntityManager#detach()operations.While
mergeanddetachcan be useful in contexts where entities are being serialized:EntityManager#clear()is a much better API for long-running and multi-threaded processesEntityManager#merge()was to merge data without further queries (when avoidable): the Second Level Cache now solves that problem in a more elegant way.TODO:
ObjectManager#detach()andObjectManager#merge()~~~ (or provide empty implementation that throws, for now)