<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Gediminas Rimša</title>
    <description>Gediminas Rimša sharing ideas he considers essential for building software well.</description>
    <link>https://g.rimsa.lt/</link>
    <atom:link href="https://g.rimsa.lt/feed.xml" rel="self" type="application/rss+xml" />
    
      <item>
        <title>On complexity</title>
        <description>&lt;blockquote&gt;
  &lt;p&gt;“The biggest problem in the development and maintenance of large-scale software systems is complexity — large systems are hard to understand.” — Ben Moseley and Peter Marks&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;the-ceiling-of-complexity&quot;&gt;The ceiling of complexity&lt;/h3&gt;

&lt;p&gt;In the preface of the &lt;em&gt;Domain-Driven Design&lt;/em&gt; book, Eric Evans mentions &lt;em&gt;the ceiling of complexity&lt;/em&gt; in passing.&lt;/p&gt;

&lt;p&gt;We can think about it as a natural limit of how complex a system can become before becoming intellectually unmanageable.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;https://g.rimsa.lt/assets/ceiling-of-complexity.gif&quot; alt=&quot;Diagram showing how effort grows exponentially as complexity increases&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As we approach this limit, the system is more and more difficult to develop and maintain, causing us to expend huge resources or gamble on our changes not breaking anything.&lt;/p&gt;

&lt;h3 id=&quot;essence-and-accident&quot;&gt;Essence and accident&lt;/h3&gt;

&lt;p&gt;A useful mental model for thinking about complexity is dividing it into two kinds: essential and accidental.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Essential complexity&lt;/strong&gt; is inherent in the problem being solved.
In other words, it is &lt;em&gt;the heart of software&lt;/em&gt;, a reflection of user expectations and intricacies of the real world, that we would still have to deal with even if we had complete knowledge, perfect tools and infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Accidental complexity&lt;/strong&gt; is then all other complexity.&lt;/p&gt;

&lt;p&gt;Expressing some idea in a programming language adds some accidental complexity. So does using a library or framework. So does every line of code that can be simplified or removed, every workaround, every purely technical feature.&lt;/p&gt;

&lt;h3 id=&quot;complexity-breeds-complexity&quot;&gt;Complexity breeds complexity&lt;/h3&gt;

&lt;p&gt;What is worse, complexity breeds complexity.&lt;/p&gt;

&lt;p&gt;Not being able to clearly understand the system makes us duplicate code, come up with poor designs and abstractions, or place them in suboptimal locations.
Using outdated technology adds otherwise unnecessary constraints, limiting our options and forcing to use workarounds.&lt;/p&gt;

&lt;p&gt;All of the above introduce further accidental complexity, compounding our difficulties.&lt;/p&gt;

&lt;h3 id=&quot;the-goal&quot;&gt;The goal&lt;/h3&gt;

&lt;p&gt;It seems natural that &lt;strong&gt;our goal should be to eliminate as much accidental complexity as possible&lt;/strong&gt;.&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;https://g.rimsa.lt/assets/reducing-accidental-complexity.gif&quot; alt=&quot;Diagram showing elimination of accidental complexity&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This way we can both make the system easier to understand and make more room for the essential.&lt;/p&gt;

&lt;p&gt;However, why is then dealing with accidental rather than essential so much of what we do?&lt;/p&gt;

&lt;h3 id=&quot;simplicity-is-not-easy&quot;&gt;Simplicity is not easy&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;“I have made this letter longer than usual, only because I have not had the time to make it shorter.” — Blaise Pascal&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The first solution is rarely the most simple, particularly if there is existing complexity, time pressure or we are new to the problem domain.&lt;/p&gt;

&lt;p&gt;There is one important distinction - &lt;em&gt;simple&lt;/em&gt; is not the same as &lt;em&gt;easy&lt;/em&gt;.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Simple&lt;/strong&gt; is the opposite of &lt;strong&gt;complex&lt;/strong&gt;. Both of these words express &lt;strong&gt;complexity&lt;/strong&gt;, which is objective and describes to what extent the parts (e.g. concepts and responsibilities) are intertwined or connected.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Easy&lt;/strong&gt; is the opposite of &lt;strong&gt;difficult&lt;/strong&gt;. Both of these words express &lt;strong&gt;effort&lt;/strong&gt;, which is subjective, meaning something difficult for me might be easy for you.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finding &lt;em&gt;simple&lt;/em&gt; solutions and concise ways to express them might be difficult.
It might require significant effort to reflect and iterate on the solution in order to untangle the complexity, identify and separate the concerns and express them clearly using fitting technology.&lt;/p&gt;

&lt;p&gt;On the other hand, an &lt;em&gt;easy&lt;/em&gt; solution that just works, might carry a lot of unnecessary complexity with it.
We rarely consider that a familiar, available, succinctly described solution might make us end up worse than before.&lt;/p&gt;

&lt;h3 id=&quot;so-where-does-this-leave-us&quot;&gt;So where does this leave us?&lt;/h3&gt;

&lt;p&gt;There is no &lt;em&gt;easy&lt;/em&gt; way out of this, no silver bullet.&lt;/p&gt;

&lt;p&gt;But we can be mindful of accidental complexity in our systems.&lt;/p&gt;

&lt;p&gt;Once we learn to spot it, we can rally our peers to practice simplicity with us — both by trying to come up with better designs and writing cleaner, more expressive code.&lt;/p&gt;

&lt;p&gt;Improving our collective skills makes simplicity easier to achieve, ultimately making it easier for us to cope with our systems.&lt;/p&gt;

&lt;h3 id=&quot;exploring-this-further&quot;&gt;Exploring this further&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;http://worrydream.com/refs/Brooks-NoSilverBullet.pdf&quot;&gt;No silver bullet: Essence and accidents of software engineering&lt;/a&gt; - essay by Fred Brooks, 1986.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://moss.cs.iit.edu/cs100/papers/out-of-the-tar-pit.pdf&quot;&gt;Out of the tar pit&lt;/a&gt; - a paper by Ben Moseley and Peter Marks, 2006.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.infoq.com/presentations/Simple-Made-Easy&quot;&gt;Simple made easy&lt;/a&gt; - a talk by Rich Hickey, 2011.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/179133.Domain_Driven_Design&quot;&gt;Domain-driven design: Tackling complexity in the heart of software&lt;/a&gt; - a book by Eric Evans, 2003.&lt;/li&gt;
&lt;/ol&gt;
</description>
        <pubDate>Tue, 08 Jan 2019 08:00:00 +0000</pubDate>
        <link>https://g.rimsa.lt/on-complexity/</link>
        <guid isPermaLink="true">https://g.rimsa.lt/on-complexity/</guid>
      </item>
    
      <item>
        <title>A hack to expose RESTful services via SOAP</title>
        <description>&lt;p&gt;Working in a corporation you sometimes face constraints that would seem strange and artificial to someone working in a small company.
However, overcoming these constraints is both challenging and fun.&lt;/p&gt;

&lt;p&gt;One of such cases is described below.&lt;/p&gt;

&lt;h2 id=&quot;the-challenge&quot;&gt;The challenge&lt;/h2&gt;
&lt;p&gt;We were building a new REST API.
A good part of it was already done when we discovered a limitation in provided infrastructure: our Enterprise Service Bus (ESB) could only expose SOAP services.&lt;/p&gt;

&lt;p&gt;REST support was promised to come soon, but we had to expose our functionality to the clients before that.&lt;/p&gt;

&lt;p&gt;The easy solution would have been to build a throwaway SOAP API and ask our clients to upgrade to REST later.
However, adding an unwelcome SOAP API did not feel right.&lt;/p&gt;

&lt;h2 id=&quot;the-solution&quot;&gt;The solution&lt;/h2&gt;

&lt;p&gt;What felt right was solving this challenge in a generic way that would require almost no extra work on both service provider and service consumer sides.&lt;/p&gt;

&lt;p&gt;The idea was to use SOAP messages for transferring request and response data, yet make them invisible to both service providers and consumers.&lt;/p&gt;

&lt;p&gt;If direct access to a REST API looked like this:&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;https://g.rimsa.lt/assets/rest.png&quot; alt=&quot;Diagram of REST&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Then this is the &lt;em&gt;REST via SOAP&lt;/em&gt; solution:&lt;/p&gt;

&lt;p class=&quot;center&quot;&gt;&lt;img src=&quot;https://g.rimsa.lt/assets/rest-via-soap.png&quot; alt=&quot;Diagram of REST via SOAP&quot; /&gt;&lt;/p&gt;

&lt;h4 id=&quot;how-does-it-work&quot;&gt;How does it work?&lt;/h4&gt;

&lt;p&gt;Let’s say we have a REST API that allows its clients to create Greeting instances.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The client then sends a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;POST&lt;/code&gt; request with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{ &quot;content&quot; : &quot;Hello!&quot; }&lt;/code&gt; body to a remote &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/api/greetings&lt;/code&gt; endpoint.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;REST Interceptor&lt;/em&gt; captures this outgoing HTTP request, transforms it into a SOAP request seen below and sends it to a remote &lt;em&gt;SOAP Proxy for REST API&lt;/em&gt; (e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/soap-api&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;soapenv:Envelope&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;xmlns:soapenv=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://schemas.xmlsoap.org/soap/envelope/&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;xmlns=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://g.rimsa.lt/rest-via-soap/&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;soapenv:Header&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;soapenv:Body&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;request&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;method=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;POST&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;path=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/api/greetings&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      { &quot;content&quot; : &quot;Hello!&quot; }
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/request&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/soapenv:Body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/soapenv:Envelope&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ol start=&quot;3&quot;&gt;
  &lt;li&gt;&lt;em&gt;SOAP Proxy&lt;/em&gt; parses the incoming SOAP message, rebuilds the REST request and forwards it to the &lt;em&gt;REST API&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;REST API&lt;/em&gt; responds with HTTP status &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;200&lt;/code&gt; and response body &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{ &quot;id&quot; : 123 }&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;SOAP Proxy&lt;/em&gt; wraps this response into a SOAP message:&lt;/li&gt;
&lt;/ol&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;SOAP-ENV:Envelope&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;xmlns:SOAP-ENV=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://schemas.xmlsoap.org/soap/envelope/&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;xmlns=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://g.rimsa.lt/rest-via-soap/&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;SOAP-ENV:Header/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;SOAP-ENV:Body&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;response&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;status=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;200&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      { &quot;id&quot; : 123 }
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/response&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/SOAP-ENV:Body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/SOAP-ENV:Envelope&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ol start=&quot;6&quot;&gt;
  &lt;li&gt;&lt;em&gt;REST Interceptor&lt;/em&gt; unwraps it and the client receives a regular HTTP response with status &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;200&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{ &quot;id&quot; : 123 }&lt;/code&gt; as the body, same as via a direct call to &lt;em&gt;REST API&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;the-implementation&quot;&gt;The implementation&lt;/h2&gt;
&lt;p&gt;When this &lt;em&gt;REST via SOAP&lt;/em&gt; idea was born, I set out to write a generic Servlet Filter to act as the &lt;em&gt;SOAP Proxy for REST API&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;It turned out well and you can now find the code in &lt;a href=&quot;https://github.com/grimsa/rest-via-soap&quot;&gt;&lt;em&gt;REST via SOAP&lt;/em&gt; project on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, as we ended up not needing it in the project we were doing at the time, it was not tested in a real-world setting and the &lt;em&gt;REST Interceptor&lt;/em&gt; part remains to be implemented.&lt;/p&gt;
</description>
        <pubDate>Wed, 08 Feb 2017 07:12:47 +0000</pubDate>
        <link>https://g.rimsa.lt/rest-via-soap/</link>
        <guid isPermaLink="true">https://g.rimsa.lt/rest-via-soap/</guid>
      </item>
    
      <item>
        <title>Hibernate: Multi-table update/delete handling strategies</title>
        <description>&lt;p&gt;If you ever used a hierarchical entity model with Hibernate, you might have noticed similar DDL statements being generated on application startup:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;declare&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;global&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;temporary&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;table&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HT_PARENT_1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ID&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;varchar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;36&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logged&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;declare&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;global&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;temporary&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;table&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HT_CHILD_1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ID&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;varchar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;36&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logged&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;declare&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;global&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;temporary&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;table&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HT_CHILD_2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ID&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;varchar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;36&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logged&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;What’s going on here? Let’s take a closer look.&lt;/p&gt;

&lt;h2 id=&quot;entity-inheritance-mapping&quot;&gt;Entity inheritance mapping&lt;/h2&gt;

&lt;p&gt;Consider the following entity hierarchy:&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@Entity&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Table&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;EMPLOYEE&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Inheritance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strategy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;InheritanceType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;JOINED&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;abstract&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Employee&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@Id&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@Column&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;ID&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;36&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;UUID&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;employeeId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;@Entity&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Table&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;EMPLOYEE_FULL_TIME&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FullTimeEmployee&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Employee&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;salary&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;@Entity&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Table&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;EMPLOYEE_PART_TIME&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;PartTimeEmployee&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Employee&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hourlyWage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InheritanceType.JOINED&lt;/code&gt; is used, the entity hierarchy is mapped to the following database schema:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;create&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;table&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EMPLOYEE&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ID&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;varchar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;36&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;primary&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;create&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;table&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EMPLOYEE_FULL_TIME&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ID&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;varchar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;36&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;salary&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;integer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;primary&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;create&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;table&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EMPLOYEE_PART_TIME&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ID&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;varchar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;36&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hourlyWage&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;primary&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;alter&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;table&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EMPLOYEE_FULL_TIME&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;constraint&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FK_emp_id_ft&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;foreign&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;references&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EMPLOYEE&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;alter&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;table&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EMPLOYEE_PART_TIME&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;constraint&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FK_emp_id_pt&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;foreign&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;references&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EMPLOYEE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A fairly straightforward mapping. But what happens once a bulk update or delete operation is executed?&lt;/p&gt;

&lt;h2 id=&quot;bulk-updates-and-deletes&quot;&gt;Bulk updates and deletes&lt;/h2&gt;

&lt;p&gt;There are some challenges explained well in this &lt;a href=&quot;http://in.relation.to/2005/07/20/multitable-bulk-operations/&quot;&gt;Multi-table Bulk Operations&lt;/a&gt; post. The essence is that, for example, deleting a multi-table entity (like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FullTimeEmployee&lt;/code&gt;) means:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Finding IDs for rows that need to be deleted and storing them somewhere&lt;/li&gt;
  &lt;li&gt;Deleting rows from multiple tables (in proper order!) by previously stored ID values&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you see, the IDs have to be stored somewhere. Let’s consider two approaches.&lt;/p&gt;

&lt;h4 id=&quot;in-memory-approach&quot;&gt;In-memory approach&lt;/h4&gt;

&lt;p&gt;An obvious approach is to keep the IDs around in application’s memory. The following SQL statements would have to be generated then:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ID&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EMPLOYEE_FULL_TIME&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SALARY&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1000000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;delete&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EMPLOYEE_FULL_TIME&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ID&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;IN&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IDs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;delete&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EMPLOYEE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ID&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;IN&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IDs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;However, the simplicity of this approach carries a performance penalty (transferring IDs over network, mapping them to/from Java objects, etc.).&lt;/p&gt;

&lt;h4 id=&quot;table-based-approach&quot;&gt;Table-based approach&lt;/h4&gt;

&lt;p&gt;A more performant approach is to store the selected ID values on the database server itself. The generated SQL would be similar to this:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;insert&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;into&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ID_TABLE&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ID&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EMPLOYEE_FULL_TIME&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SALARY&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1000000&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;delete&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EMPLOYEE_FULL_TIME&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;IN&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ID&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ID_TABLE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;delete&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EMPLOYEE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;IN&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ID&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ID_TABLE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note that as different entities could have different ID definitions, an equivalent of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ID_TABLE&lt;/code&gt; needs to exist for each entity that is a part of any entity hierarchy. That could be a significant number of tables.&lt;/p&gt;

&lt;p&gt;Let’s take a look at what Hibernate can do for us here.&lt;/p&gt;

&lt;h2 id=&quot;hibernates-multitablebulkidstrategy-implementations&quot;&gt;Hibernate’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MultiTableBulkIdStrategy&lt;/code&gt; implementations&lt;/h2&gt;

&lt;p&gt;Hibernate has defined a generalized interface for handling multi-table bulk HQL operations called  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MultiTableBulkIdStrategy&lt;/code&gt;. Currently (Hibernate 5.2.6) ships with three implementations of this interface, all of them table-based:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GlobalTemporaryTableBulkIdStrategy&lt;/code&gt; - based on ANSI SQL’s definition of a “global temporary table”.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LocalTemporaryTableBulkIdStrategy&lt;/code&gt; - based on ANSI SQL’s definition of a “local temporary table” (local to each database session).&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PersistentTableBulkIdStrategy&lt;/code&gt; - based on regular tables with an extra &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hib_sess_id&lt;/code&gt; column to segment rows from different Hibernate sessions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The strategy to use is determined by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hibernate.hql.bulk_id_strategy&lt;/code&gt; property, with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Dialect#getDefaultMultiTableBulkIdStrategy&lt;/code&gt; used as a fallback.&lt;/p&gt;

&lt;h4 id=&quot;table-creation-at-startup&quot;&gt;Table-creation at startup&lt;/h4&gt;

&lt;p&gt;Both &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GlobalTemporaryTableBulkIdStrategy&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PersistentTableBulkIdStrategy&lt;/code&gt; try to create the ID tables at startup and that is where the DDL statements mentioned in the beginning of the post come from.&lt;/p&gt;

&lt;p&gt;It’s worth noting that any of these DDL statements that fail are just logged at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DEBUG&lt;/code&gt; level and quietly ignored. That is, until a bulk update or delete operation is executed, at which point it would fail if the required table does not exist.&lt;/p&gt;

&lt;p&gt;The point here is that failing to create the ID tables does not prevent application from starting and working, as long as:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;No bulk update or delete operations are used, or&lt;/li&gt;
  &lt;li&gt;The ID tables are pre-created by other means (e.g. by a DBA having required authorizations).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are also alternative implementations that might be useful in some circumstances.&lt;/p&gt;

&lt;h2 id=&quot;alternative-implementations&quot;&gt;Alternative implementations&lt;/h2&gt;

&lt;p&gt;Alternative strategy implementations discussed below might help you when:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;DDL statements cannot be executed by your application&lt;/li&gt;
  &lt;li&gt;Bulk update/delete operations are actually used&lt;/li&gt;
  &lt;li&gt;Pre-creating ID tables is either difficult or impossible&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;when-pre-creating-id-tables-is-difficult&quot;&gt;When pre-creating ID tables is difficult&lt;/h4&gt;

&lt;p&gt;Assume there’s a way for you to get the ID tables created, either by doing some manual work or by involving other parties who can do it for you.&lt;/p&gt;

&lt;p&gt;If your entity model is stable, you might just bite the bullet and do the work to create the ID tables once and for all. Afterwards you could forget about it and stick with using one of Hibernate’s standard strategies. However, if your model is constantly evolving, you might want to alleviate the pain of dealing with extra ID tables.&lt;/p&gt;

&lt;p&gt;For this purpose I created a &lt;a href=&quot;https://github.com/grimsa/hibernate-single-table-bulk-id-strategy&quot;&gt;Single Global Temporary Table Bulk Id Strategy&lt;/a&gt;. It’s a slightly modified &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GlobalTemporaryTableBulkIdStrategy&lt;/code&gt; that uses a single shared global temporary table to store IDs for all entities, segmenting the rows by entity name held in an extra column.&lt;/p&gt;

&lt;p&gt;The benefit of it is that you retain the advantages of the table-based approach, while also minimizing the overhead to create and manage tables for each entity.&lt;/p&gt;

&lt;p&gt;The strategy was developed for a project where the same ID type and column name was used across all entities. Naturally, the same type and name was also used for the shared ID table too.&lt;/p&gt;

&lt;p&gt;It should either work out-of-the-box or be easily extendable to support other cases (different types and/or names of single-column IDs, maybe even multi-column IDs), but you should verify it works for your circumstances.&lt;/p&gt;

&lt;h4 id=&quot;when-pre-creating-id-tables-is-impossible&quot;&gt;When pre-creating ID tables is impossible&lt;/h4&gt;

&lt;p&gt;If there’s no way to create the ID tables at all, then any of the built-in table-based strategies are not an option. In this case you’d have to turn to the in-memory approach, which, to my surprise, is not implemented in Hibernate.&lt;/p&gt;

&lt;p&gt;Luckily, there’s &lt;a href=&quot;https://github.com/epiresdasilva/cte-multi-table-bulk-id-stategy&quot;&gt;CTE Bulk Id Strategy&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The project includes tests on PostgreSQL, although when I tried it on DB2 and H2 databases a while ago, it did not work. Hence, minor alterations might once again be needed.&lt;/p&gt;

&lt;h2 id=&quot;in-place-of-a-summary&quot;&gt;In place of a summary&lt;/h2&gt;

&lt;p&gt;The need for bulk update or delete operations (based on non-PK columns) on entity hierarchies is not a very common one, and Hibernate’s ID table-based strategies cover this need well in most environments.&lt;/p&gt;

&lt;p&gt;However, when creation of ID tables is either problematic or not possible, one of existing alternative &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MultiTableBulkIdStrategy&lt;/code&gt; implementations could be used.&lt;/p&gt;

&lt;p&gt;Or, as they say, you can always roll your own.&lt;/p&gt;

&lt;h2 id=&quot;2017-07-18-update&quot;&gt;2017-07-18 Update&lt;/h2&gt;

&lt;p&gt;Hibernate 5.2.8 added a number of new &lt;a href=&quot;http://in.relation.to/2017/02/01/non-temporary-table-bulk-id-strategies/&quot;&gt;Bulk-id strategies when you can’t use temporary tables&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;These new strategies have only slight differences and a good starting point is to go with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InlineIdsOrClauseBulkIdStrategy&lt;/code&gt;, which is supported by all major relational database systems.&lt;/p&gt;
</description>
        <pubDate>Sat, 24 Dec 2016 15:20:47 +0000</pubDate>
        <link>https://g.rimsa.lt/hibernate-multi-table-bulk-id-strategies/</link>
        <guid isPermaLink="true">https://g.rimsa.lt/hibernate-multi-table-bulk-id-strategies/</guid>
      </item>
    
  </channel>
</rss>
