I have an audit mechanism for a project built with ef-core code first approach. I've set the "DeleteBehavior" property to cascade for some tables in "OnModelCreating" function. When I delete an entity, the other one deleted automaticly by cascade delete behavior. That's all good for now and I need to get all deleted entities, but I cannot. The ChangeTracker doesn't contain the cascade deleted entities. How can I get the cascade deleted values? Is there any way to do this?
Cascade Delete happen on the database side. Entity Framework doesn't need to be aware which entity will be deleted.
Entity Framework only tracks changes and delete the base object.
Edit: Answer subquestions
You are right. I'm the owner of EF+.
Technically, a library could handle this, but this will come with a severe performance drawback. I'm not aware of any feature or library which handle the cascade delete scenario for auditing.
Suggestion?
There is some suggestion, but I'm pretty sure you will not like any of them, and I don't either recommend them for performance reason:
Do not use cascade delete (force you also retrieving/deleting related entities)
Create ON DELETE Trigger and Log at database side.
I don't think a good solution exists for this scenario.
Related
I manage complex entities, with multiple and different relationships with other entities, which themselves are linked to multiple other entities sometime.
I am making an edit form, and would like to avoid having to code manually different Doctrine 2 queries to udpate every entity linked to the modified entity.
Is it possible to cascade merge entities in Doctrine 2 ? By that, I mean modifying an entity and its linked entities (oneToMany, ManyToMany... relationships) and then applying the changes to the entity and the linked entities in cascade.
If not, what is the 'clean' way to apply modifications to all the concerned entities ? Does it need to be manually done, by calling merge or update on every entity ?
It seems you are working on Symfony (correct me if I'm wrong).
On symfony forms, when you are working with underlying objects, you sometimes need to put 'by_reference' option to 'false' in order to correctly handle the underlying modified objects.
See that : https://symfony.com/doc/current/reference/forms/types/form.html#by-reference
Hope it helps.
Most probably the problem has nothing to do with symfony but more with your doctrine relationships. You should check your associations as changes made only to the inverse side of an association are ignored by doctrine. Refer to the documentation.
Anyone has idea why Firebird update and delete foreign key rule, work in a inverse logical?
When you changes some data and it is a FK, the Firebird behavior :
First: delete master
After: delete details
When my guess that correct behavior would be:
First: delete details
After: delete master
This a big problem when you try to replicate the data to another database in runtime.
It is the delete on master that causes the cascading delete. On an implementation level this is handled by a system trigger on the table, therefor the delete on the master has to happen first, and the delete from details is the result of that.
I don't know how you are replicating the data, but you might want to check if you are using BEFORE or AFTER triggers to do this (however I don't know if changing BEFORE to AFTER would change firing order to detail-master).
For more detailed information on implementation and limitation, you might want to post a question on the firebird-devel mailinglist. There are people following that list who have also built replication software, and the core Firebird developers might provide more detailed info.
What are the practical advantages of Doctrine Migrations over just running a schema update?
Safety?
The orm:schema-tool:update command (doctrine:schema:update in Symfony) warns
This operation should not be executed in a production environment.
but why is this? Sure, it can delete data but so can a migration.
Flexibility?
I thought I could tailor my migrations to add stuff like column defaults but this often doesn't work as Doctrine will notice the discrepancy between the schema and the code on the next diff and stomp over your changes.
When you are using the schema-tool, no history of database modification is kept, and in a production/staging environment this is a big downside.
Let's assume you have a complicated database structure in a live project. And in the next changeset you have to alter the database somehow. For example, your users' contact phones need to be stored in a different format, not a VARCHAR, but three SMALLINT columns for country code, area code and the phone number.
Well, that's not so hard to figure out a query that would fetch the current data, separate it into three values and insert them back. That's when migrations come into play: you can create your new fields, then do the transforms and finally drop the field that was holding the data before.
And even more! You can even describe the backwards process (the down migration), when you need to undo the changes introduced in your migration. Let's assume that someone somewhere relied heavily on the format of the VARCHAR field, and now that you've changed the structure, his piece of code is not working as expected. So, you run migration:down, and everything gets reverted. In this specific case you'd just bring back the old VARCHAR column and concatenate the values back, and then drop the fields.
Doctrine's migration tool basically does most of the work for you. When you diff your schema, it generates all the necessary up's and down's, so only thing you'll have to do is handle the data that could be damaged when the migration is applied.
Also, migrations are something that gives other developers on your team knowledge on when it's time to update their schemas. With just the schema-tool, your teammates would have to run doctrine:schema:update each and every time they pull, `cause they wouldn't know if the schema has really changed.
When using migrations, you always see that there are some updates in the migrations folder, which means you need to update your schema.
I think that you indeed nailed it on Safety. With Migrations you can go back to another state of the table (just like you can do in Git version control). With the schema update command you can only UPDATE the tables. There is no log kept for going back in case of a failure with already saved data in those tables. I don't know exactly, but doesn't a migration also saves the data of the corresponding table that's being updated? That would be essential in my opinion, otherwise there is no big reason to use them.
So yes, I personally think that the main reason for using migrations in a production environment is safety and maybe a bit of flexibility. Safety would be the winner here I think :)
Hope this helps.
edit: Here is another answer with references to the Symfony docs: Is it safe to use doctrine2 migrations in production environment with symfony2 and php
You also cant perform large updates with plain doctrine migration. Like try to update index on 30 mln users database. As it will a lot of time while you app will not be accessible.
In doctrine documentation I found: "By default, no operations are cascaded." (here http://bit.ly/1frPyLH)
But still one of my database entities is persisting it's associated objects, besides the fact that it has no cascade option in the association.
How can I prevent it from persisting the associated entities ?
It is true and the documentation is still not wrong. =P
Without going deeper on your problem, you need to be aware that by default Doctrine applies a concept called "persistence by reachability". This means that if you are creating a new entity and one of your associations is already managed by UnitOfWork (already known by Doctrine), it will "cascade" the operation.
The problem here is how you read about cascading. In reality, it's not the cascading factor that is updating the associated entity, but it's because it's already managed by Doctrine.
To solve this "problem", you need to modify the way you want Doctrine to deal with your entities by altering the Change Tracking Policy.
I hope this gives you enough information to solve your issue.
I have an entity (eg Image) which is related to many other entities (eg Product or Category). I would like to know which is the best way to prevent the removal of an entity if a relation exists somewhere else (eg I should not be able to delete an Image if it is related to a product). My thoughts are either searching for relations in a repository class and returning results, or doing 'something' at the preRemove lifecycle event of the entity. Which is the best Symfony2 way for preventing removal of related entities?
As long as cascade delete is not set, any directionally entity will prevent delete of the related entity. If your associations are not birectional, you'll have to query form the backside as well.
To expand upon CJ's answer, you may remove delete links, but you will also have to check the entity in controller as well, because any url hacker can delete an object if its id is known.
What I would suggest is you can better of disabled the form delete link when there is a relationship between entities. In that way you can even make the customer understand that there is related entity and he should not remove it before removing the relationship.
You can always check the entity before deleting it and when you actually call certain process in symfony on an entity you actually work on the entire object of that particular entity which gives access to all the values of that entity. So you can check it at that particular point and make conditional statement.
It my personal believe that you should not try to import excess library functions for minor things which can be achieved by you without them. this would make you code easier to understand and even lighter as the prospect for including extra libraries which will most likely have more than what you need