CINXE.COM
SoftDelete | Ebean
<!doctype html> <html lang="en"> <head> <title>SoftDelete | Ebean</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <link rel="shortcut icon" href="/images/favicon.ico"> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto|Source+Sans+Pro|Ubuntu&display=swap"> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/all.css" integrity="sha384-lKuwvrZot6UHsBSfcMvOkWwlCMgc0TaWr+30HWe3a4ltaBwTZhyTEggF5tJv8tbt" crossorigin="anonymous"> <link rel="stylesheet" href="/css/reset3.css"> <link rel="stylesheet" href="/css/site3.css"> <link rel="stylesheet" href="/css/pygments3.css"> </head> <body> <div id="main"> <div id="banner"> <header> <nav id="top"> <h1 id="breadcrumb"> <a class="nav-logo" href="/"><img src="/images/logo-200.png" height="35"></a> <a href="/docs">Documentation</a><span class="sep"> / </span><a href="/docs/features/">Features</a><span class="sep"> / </span><span class="last">SoftDelete</span> </h1> <ul> <li><a onclick="toggleTheme();" title="switch dark light theme"><i class="fas fa-adjust"></i></a></li> </ul> </nav> </header> </div> <div class="grid grid-docs"> <aside> <nav class="side"> <ul> <li class="nav0 "> <a href="/docs/getting-started">Getting started</a> </li> <li class="nav0 "> <a href="/docs/intro">Introduction</a> </li> <li class="nav0 active"> <a class="active" href="/docs">Documentation</a> <ul> <li class="nav1 "> <a href="/docs/best-practice">Best practice</a> </li> <li class="nav1 "> <a href="/docs/query">Query</a> </li> <li class="nav1 "> <a href="/docs/persist">Persist</a> </li> <li class="nav1 "> <a href="/docs/transactions">Transactions</a> </li> <li class="nav1 "> <a href="/docs/mapping">Mapping</a> </li> <li class="nav1 "> <a href="/docs/ddl-generation">DDL & Migrations</a> </li> <li class="nav1 "> <a href="/docs/logging">Logging</a> </li> <li class="nav1 "> <a href="/docs/testing">Testing</a> </li> <li class="nav1 "> <a href="/docs/read-replicas">Read Replicas</a> </li> <li class="nav1 "> <a href="/docs/database">Database platforms</a> </li> <li class="nav1 "> <a href="/docs/multi-database">Multiple databases</a> </li> <li class="nav1 "> <a href="/docs/kotlin">Kotlin</a> </li> <li><a href="/docs/tuning">Tuning</a></li> <li class="nav1 active"> <a class="active" href="/docs/features">Features</a> <ul class="nav"> <li > <a href="/docs/features/l2cache">L2 Cache</a> </li> <li > <a href="/docs/features/elasticsearch">Elasticsearch</a> </li> <li > <a href="/docs/features/json-in-db">@DbJson</a> </li> <li class="active"> <a class="active" href="/docs/features/softdelete">Soft Delete</a> </li> <li > <a href="/docs/features/encryption">Encryption</a> </li> <li > <a href="/docs/features/who">@WhoModified / @WhoCreated</a> </li> <li > <a href="/docs/features/history">SQL2011 History</a> </li> <li > <a href="/docs/features/changelog">ChangeLog</a> </li> <li > <a href="/docs/features/readauditing">Read auditing</a> </li> <li > <a href="/docs/features/eventlistening">Event Listening</a> </li> </ul> </li> </ul> </li> <li class="nav0 "> <a href="/support">Getting help</a> </li> <li class="nav0 "> <a target="_blank" href="/apidoc/13">API Javadoc</a> </li> <li class="nav0 "> <a href="/videos">Videos</a> </li> <li class="nav0 "> <a href="/docs/upgrading">Upgrading</a> </li> <li class="nav0 "> <a href="/releases">Releases</a> </li> </ul> </nav> </aside> <article> <form action="https://www.google.com/search" method="get" class="inline-form"> <input type="hidden" name="as_sitesearch" value="ebean.io"> <div id="page-search"> <div class="input-group"> <input class="frm" name="q" id="searchinput" type="text" placeholder="Search... (press 's' to focus)" data-placeholder-focus="Search... (use '↑', '↓' and '⏎' to select results)" data-placeholder-blur="Search... (press 's' to focus)" autocomplete="off"> <div class="input-group-btn"> <button class="frm" type="submit"><i class="fas fa-search"></i></button> </div> </div> <div id="page-search-results" style="display: none;"> <ul id="search-results-container" class="search-results"><li class=" active"><a href="/docs" title="Docs"><span style="color:#777;">Docs</span> Documentation </a></li><li class=""><small style="color:#999;">And 101 more...</small></li></ul> </div> </div> </form> <h2 id="softdelete">@SoftDelete</h2> <p> Add a boolean property to your entity beans to indicate the deleted state. This property can be on the entity bean or on a MappedSuperclass as per the example below: </p> <p> This property must be a boolean type with a true value meaning that the row/bean has been logically deleted. </p> <div class="syntax java"><div class="highlight"><pre><span></span><span class="nd">@MappedSuperclass</span> <span class="kd">public</span> <span class="kd">class</span> <span class="nc">BaseSoftDelete</span> <span class="o">{</span> <span class="nd">@Id</span> <span class="n">Long</span> <span class="n">id</span><span class="o">;</span> <span class="nd">@Version</span> <span class="n">Long</span> <span class="n">version</span><span class="o">;</span> <span class="nd">@SoftDelete</span> <span class="kt">boolean</span> <span class="n">deleted</span><span class="o">;</span> </pre></div> </div> <h2 id="delete">Delete</h2> <p> A delete of an entity bean that has SoftDelete becomes a SQL update. </p> <div class="syntax java"><div class="highlight"><pre><span></span><span class="c1">// delete becomes an update if the bean has soft delete property</span> <span class="n">database</span><span class="o">.</span><span class="na">delete</span><span class="o">(</span><span class="n">bean</span><span class="o">);</span> </pre></div> </div> <div class="syntax sql"><div class="highlight"><pre><span></span><span class="c1">-- soft delete ... sets deleted = true</span> <span class="k">update</span> <span class="n">mybean</span> <span class="k">set</span> <span class="k">version</span><span class="o">=?</span><span class="p">,</span> <span class="n">deleted</span><span class="o">=?</span> <span class="k">where</span> <span class="n">id</span><span class="o">=?</span> <span class="k">and</span> <span class="k">version</span><span class="o">=?</span><span class="p">;</span> <span class="c1">--bind(2,true,1,1,)</span> </pre></div> </div> <h2 id="deletepermanent">Delete Permanent</h2> <p> Delete permanent is used to perform a SQL delete (hard delete). </p> <div class="syntax java"><div class="highlight"><pre><span></span><span class="c1">// delete becomes an update if the bean has soft delete property</span> <span class="n">database</span><span class="o">.</span><span class="na">deletePermanent</span><span class="o">(</span><span class="n">bean</span><span class="o">);</span> </pre></div> </div> <div class="syntax sql"><div class="highlight"><pre><span></span><span class="c1">-- delete permanent</span> <span class="k">delete</span> <span class="k">from</span> <span class="n">mybean</span> <span class="k">where</span> <span class="n">id</span><span class="o">=?</span> <span class="k">and</span> <span class="k">version</span><span class="o">=?</span><span class="p">;</span> <span class="c1">--bind(1,2,)</span> </pre></div> </div> <h2 id="cascade">Cascading behavior</h2> <p> A soft delete will cascade along the same relationships as a hard delete as long as the beans support soft delete. If the 'target' bean does not have a <code>@SoftDelete</code> property (and hence does not support soft delete) then the soft delete will not cascade to that relationship. </p> <h4>ManyToMany</h4> <p> Soft delete will not cascade to the intersection table of a <code>@ManyToMany</code>. </p> <h4>Draftable</h4> <p> Soft delete will not propagate to the associated "live" row of a @Draftable entity bean. </p> <h2 id="query">Query (normal)</h2> <p> A normal query automatically includes a predicate to filter out soft deleted rows. A predicate is added for each table (SQL FROM or JOIN) that has a soft delete column. This is done for any subsequent lazy loading queries as necessary. </p> <blockquote> and t0.deleted=false and t1.deleted=false ... additional predicates </blockquote> <div class="syntax sql"><div class="highlight"><pre><span></span><span class="k">select</span> <span class="n">t0</span><span class="p">.</span><span class="n">id</span> <span class="n">c0</span><span class="p">,</span> <span class="n">t0</span><span class="p">.</span><span class="n">name</span> <span class="p">...</span> <span class="k">from</span> <span class="n">ebasic_soft_delete</span> <span class="n">t0</span> <span class="k">left</span> <span class="k">outer</span> <span class="k">join</span> <span class="n">ebasic_sdchild</span> <span class="n">t1</span> <span class="k">on</span> <span class="n">t1</span><span class="p">.</span><span class="n">owner_id</span> <span class="o">=</span> <span class="n">t0</span><span class="p">.</span><span class="n">id</span> <span class="k">where</span> <span class="n">t0</span><span class="p">.</span><span class="n">id</span> <span class="o">=</span> <span class="o">?</span> <span class="c1">-- Additional predicates for soft delete</span> <span class="k">and</span> <span class="n">t0</span><span class="p">.</span><span class="n">deleted</span><span class="o">=</span><span class="k">false</span> <span class="k">and</span> <span class="n">t1</span><span class="p">.</span><span class="n">deleted</span><span class="o">=</span><span class="k">false</span> <span class="k">order</span> <span class="k">by</span> <span class="n">t0</span><span class="p">.</span><span class="n">id</span><span class="p">;</span> <span class="c1">--bind(1)</span> </pre></div> </div> <h2 id="includeSoftDeletes">Query - includeSoftDeletes</h2> <p> A query can have <code>includeSoftDeletes()</code> set and in this case the soft delete predicates are not added to the query and this means all rows including soft deleted rows are included in the result. </p> <blockquote> Query.includeSoftDeletes() </blockquote> <div class="syntax java"><div class="highlight"><pre><span></span><span class="c1">// find a bean that could be soft deleted</span> <span class="n">List</span><span class="o"><</span><span class="n">MyBean</span><span class="o">></span> <span class="n">beans</span> <span class="o">=</span> <span class="n">database</span><span class="o">.</span><span class="na">find</span><span class="o">(</span><span class="n">MyBean</span><span class="o">.</span><span class="na">class</span><span class="o">)</span> <span class="o">.</span><span class="na">includeSoftDeletes</span><span class="o">()</span> <span class="o">.</span><span class="na">where</span><span class="o">().</span><span class="na">icontains</span><span class="o">(</span><span class="s">"name"</span><span class="o">,</span> <span class="s">"rob"</span><span class="o">)</span> <span class="o">.</span><span class="na">findList</span><span class="o">();</span> <span class="c1">// find a bean that could be soft deleted</span> <span class="n">MyBean</span> <span class="n">bean</span> <span class="o">=</span> <span class="n">database</span><span class="o">.</span><span class="na">find</span><span class="o">(</span><span class="n">MyBean</span><span class="o">.</span><span class="na">class</span><span class="o">)</span> <span class="o">.</span><span class="na">includeSoftDeletes</span><span class="o">()</span> <span class="o">.</span><span class="na">setId</span><span class="o">(</span><span class="n">idValue</span><span class="o">)</span> <span class="o">.</span><span class="na">findOne</span><span class="o">();</span> </pre></div> </div> <h2 id="notifications">Notifications</h2> <p> For BeanPersistController, BeanPersistListener, L2 Cache and Cluster notifications a soft delete is treated the same as a hard delete and the same event notifications occur. </p> <h2 id="changelog">Change Log</h2> <p> For ChangeLog soft deletes are treated as updates as this reflects the actual change that occured. </p> </article> </div> </div> <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script> <script src="/js/site3.js"></script> <script src="/js/search3.js"></script> <script async src="https://www.googletagmanager.com/gtag/js?id=UA-75181644-1"></script> <script> window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-75181644-1'); </script> </body> </html>