

This behavior can easily be emulated for the soft deletes solution: methods=)
#Delete cascade postgres code#
where a user can only be deleted once, and any attempts to repeat the call will end with a code 404 response, indicating that the user was not found. This is a difference in behavior compared to a "hard delete" implementation. If you delete a user, and then try to delete it again, the function will still succeed. This looks pretty straightforward, right? Unfortunately, the above function has a small problem. Now that the application can record deleted users in the database, I can add a new endpoint that performs the soft delete: methods=) The implementation with a timestamp is largely identical. In this case, I'm going to add soft delete support for users: class User(db.Model):ĭeleted = db.Column(db.Boolean(), default=False)įor this example I have made the deleted column a boolean for simplicity, but in many cases it is convenient to make it a timestamp, so that you not only know what records are deleted, but also when each deletion took place. The core change is the addition of a column to the model or models that need to support the feature. The actual implementation of the soft delete feature is fairly simple. The correct thing to do is to "soft delete" users who wish to delete their accounts, and that way they can stay in the database and keep any messages written by the user consistent. Physically deleting users from the database is not a great idea, as there might be messages with their user_id foreign keys pointing at deleted users, which would leave orphaned messages at best, or trigger database consistency errors at worst. What I want to do now, is allow users to delete their accounts. Note that for this example I have not implemented authentication, since that is not the scope of this article. The complete code for the application is available on GitHub. User_id = db.Column(db.Integer, db.ForeignKey('users.id'))Īs you can see, there is nothing strange or complicated, just a database of users and messages written by them. Id = db.Column(db.Integer, primary_key=True) Below you can see the two models used by this service, before there is support for soft deletes: class User(db.Model): A Concrete ExampleĪs way of an example, I'm going to use a Flask application that implements a simple chat service. In this article I will discuss some of these issues and how I avoid them in Flask and SQLAlchemy based applications. This sounds straightforward to implement, and strictly speaking it is, but the complications that derive from the use of soft deletes are far from trivial. It does it by adding an extra column to your database table(s) that keeps track of the deleted state of each of its rows. The Soft Delete pattern is one of the available options to implement deletions without actually deleting the data. But obviously these records that you saved from permanent deletion need to be marked as being "less interesting" than the rest, so that you have something you can use to filter them out in queries. You can find lots of reasons to never delete records from your database. What if I later determine that I needed this piece of information, after all? For example, what if having access to this data that was deleted would have helped me reproduce or debug an issue? Or what if the data can be useful for audit purposes in a future version of the application? Primarily, we'll test that all its associated Comments are automatically deleted when an Article is deleted.Every time I find myself writing code to delete data from a database I get nervous. Let's test our cascading deletion using an in-mem H2 database, assuming we have set up the service and the JPA repository layers. The second option we'll use in conjunction with cascade is the orphanRemoval. If we only want to cascade the removal of child entities when the parent entity is deleted, then we can use CascadingType.Remove.

JPA also provides an option to set the cascading level for all operations. Essentially cascade allows us to define which operation (persist, merge, remove) on the parent entity should be cascaded to the related child entities. The option that can be useful for cascading delete is the cascade. This annotation can also be used with several options to customize the relationship mapping and behavior.

Let's expand on our annotation on the Set in the Article object. To solve this problem, JPA provides a few properties that can be used to propagate the deletion and to clean up orphaned objects. In the example above, if we decide to delete the Article, any Comment associated with it will be left as a dangling reference or orphaned object.
