avatarVinotech

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

10181

Abstract

hljs-keyword">public</span> <span class="hljs-title class_">Address</span> <span class="hljs-title function_">getHomeAddress</span>(<span class="hljs-params"></span>) { <span class="hljs-keyword">return</span> homeAddress; }

<span class="hljs-keyword">public</span> <span class="hljs-built_in">void</span> <span class="hljs-title function_">setHomeAddress</span>(<span class="hljs-params">Address homeAddress</span>) {
    <span class="hljs-variable language_">this</span>.<span class="hljs-property">homeAddress</span> = homeAddress;
}

}</pre></div><h2 id="d60c">@Embedded</h2><p id="189c">The <code>@Embedded</code> annotation is used to specify that a field of an entity is an instance of an <code>@Embeddable</code> class, and the properties of that <code>@Embeddable</code> class should be included in the table of the containing entity.</p><p id="180b">In this case, the <code>Employee</code> entity contains the <code>Address</code> object as a field, and it's annotated with <code>@Embedded</code>. This means the <code>homeAddress</code> field in the <code>Employee</code> entity will embed the <code>Address</code> fields (e.g., <code>street</code>, <code>zipCode</code>, and <code>city_id</code>) into the <code>employee</code> table.</p><h2 id="47f0">How It Works in the Database</h2><p id="5fcc">When <code>Address</code> is embedded in <code>Employee</code>, it means that the <code>Employee</code> entity’s table will have columns corresponding to the fields of the <code>Address</code> entity, like <code>street</code>, <code>zipCode</code>, and <code>city_id</code>. These fields won't exist in a separate <code>Address</code> table, but rather as part of the <code>employee</code> table.</p><h2 id="5abd">Key Points:</h2><ul><li><code><b>@Embeddable</b></code>: Defines a class that can be embedded in another entity.</li><li><code><b>@Embedded</b></code>: Embeds the fields of the <code>@Embeddable</code> class into the containing entity’s table.</li></ul><p id="fdbb"><code><b>OfficeEmployee</b></code><b> Entity </b>This entity extends <code>Employee</code> and overrides the relationship for work address using <code>@AssociationOverride</code>.</p><div id="ffae"><pre><span class="hljs-meta">@Entity</span> <span class="hljs-meta">@AssociationOverride</span>( name = <span class="hljs-string">"homeAddress.city"</span>, joinColumns = <span class="hljs-meta">@JoinColumn</span>(name = <span class="hljs-string">"work_city_id"</span>) <span class="hljs-comment">// Overrides the default "city_id"</span> ) <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">OfficeEmployee</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_ inherited__">Employee</span> {

<span class="hljs-meta">@Embedded</span>
<span class="hljs-meta">@AttributeOverrides</span>({
    <span class="hljs-meta">@AttributeOverride</span>(name = <span class="hljs-string">"street"</span>, column = <span class="hljs-meta">@Column</span>(name = <span class="hljs-string">"work_street"</span>)),
    <span class="hljs-meta">@AttributeOverride</span>(name = <span class="hljs-string">"zipCode"</span>, column = <span class="hljs-meta">@Column</span>(name = <span class="hljs-string">"work_zipCode"</span>))
})
<span class="hljs-keyword">private</span> <span class="hljs-title class_">Address</span> workAddress;

<span class="hljs-comment">// Constructors, getters, setters</span>
<span class="hljs-keyword">public</span> <span class="hljs-title class_">OfficeEmployee</span>() {}

<span class="hljs-keyword">public</span> <span class="hljs-title class_">OfficeEmployee</span>(<span class="hljs-title class_">String</span> name, <span class="hljs-title class_">Address</span> homeAddress, <span class="hljs-title class_">Address</span> workAddress) {
    <span class="hljs-variable language_">super</span>(name, homeAddress);
    <span class="hljs-variable language_">this</span>.<span class="hljs-property">workAddress</span> = workAddress;
}

<span class="hljs-keyword">public</span> <span class="hljs-title class_">Address</span> <span class="hljs-title function_">getWorkAddress</span>(<span class="hljs-params"></span>) {
    <span class="hljs-keyword">return</span> workAddress;
}

<span class="hljs-keyword">public</span> <span class="hljs-built_in">void</span> <span class="hljs-title function_">setWorkAddress</span>(<span class="hljs-params">Address workAddress</span>) {
    <span class="hljs-variable language_">this</span>.<span class="hljs-property">workAddress</span> = workAddress;
}

}</pre></div><h2 id="ac6c">@AssociationOverride</h2><p id="e7bb">The <code>@AssociationOverride</code> annotation allows you to override the mapping of a relationship (association) in an embedded object or in an inheritance hierarchy. This is particularly useful when you have an <code>@Embedded</code> object with associations (such as <code>@ManyToOne</code> or <code>@OneToMany</code>), and you need to change the way the relationship is mapped in a subclass or another entity.</p><ul><li><b>Purpose</b>: In this case, we are overriding the <code>city</code> relationship in the <code>homeAddress</code> field (which is an embedded <code>Address</code>) for the <code>OfficeEmployee</code> entity. The <code>@ManyToOne</code> relationship for the <code>city</code> field in the <code>homeAddress</code> is overridden to use a different column (<code>work_city_id</code>) in the database.</li><li><b>Effect</b>: This allows <code>OfficeEmployee</code> to use a different column for its city relationship compared to the <code>Employee</code> class, where the default column for <code>homeAddress.city</code> is <code>home_city_id</code>. In <code>OfficeEmployee</code>, we override this with <code>work_city_id</code> for the work address.</li></ul><h2 id="ca22">@AttributeOverrides</h2><p id="87bb">The <code>@AttributeOverrides</code> annotation allows you to override the column mappings for simple attributes in an embedded object. This is typically used to change the default column names that are automatically mapped based on the embedded object's fields.</p><ul><li><b>Purpose</b>: The <code>@AttributeOverrides</code> annotation is used to override the column names for the <code>street</code> and <code>zipCode</code> fields in the embedded <code>Address</code> object when it is mapped to <code>workAddress</code>.</li></ul><p id="d680"><b>Effect</b>:</p><ul><li>For <code>workAddress.street</code>, the column is named <code>work_street</code> instead of <code>home_street</code> (or whatever default column name would be used).</li><li>For <code>workAddress.zipCode</code>, the column is named <code>work_zipCode</code> instead of <code>home_zipCode</code>.</li></ul><h2 id="770d">Repository</h2><p id="1c49">We need repositories to perform CRUD operations on the entities.</p><p id="a21d"><code><b>CityRepository</b></code></p><div id="17c7"><pre><span class="hljs-keyword">import</span> org.springframework.<span class="hljs-keyword">data</span>.jpa.repository.JpaRepository;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title class_">CityRepository</span> <span class="hljs-title">extends</span> <span class="hljs-title">JpaRepository</span><<span class="hljs-type">City, Long</span>> {}</pre></div><p id="ca30"><b>EmployeeRepository</b></p><div id="19d4"><pre><span class="hljs-keyword">import</span> org.springframework.<span class="hljs-keyword">data</span>.jpa.repository.JpaRepository;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title class_">CityRepository</span> <span class="hljs-title">extends</span> <span class="hljs-title">JpaRepository</span><<span class="hljs-type">City, Long</span>> {}</pre></div><h2 id="13af">Service Layer</h2><p id="2130"><code><b>EmployeeService</b></code></p><div id="3692"><pre><span class="hljs-keyword">import</span> org.springframework.beans.factory.annotation.Autowired; <span class="hljs-keyword">import</span> org.springframework.stereotype.Service;

<span class="hljs-keyword">import</span> javax.transaction.Transactional;

<span class="hljs-meta">@Service</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">EmployeeService</span> {

<span class="hljs-meta">@Autowired</span>
<span class="hljs-keyword">private</span> EmployeeRepository employeeRepository;

<span class="hljs-meta">@Autowired</span>
<span class="hljs-keyword">private</span> CityRepository cityRepository;

<span class="hljs-meta">@Transactional</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">createEmployees</span><span class="hljs-params">()</span> {
    <span class="hljs-type">City</span> <span class="hljs-variable">newYork</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">City</span>(<span class="hljs-string">"New York"</span>);
    <span class="hljs-type">City</span> <span class="hljs-variable">losAngeles</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">City</span>(<span class="hljs-string">"Los Angeles"</span>);
    cityRepository.save(newYork);
    cityRepository.save(losAngeles);

    <span class="hljs-comment">// Create home address for John</span>
    <span class="hljs-type">Address</span> <span class="hljs-variable">homeAddress</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Address</span>(<span class="hljs-string">"Elm St."</span>, <span class="hljs-string">"12345"</span>, newYork);

    <span class="hljs-comment">// Create work address for John</span>
    <span class="hljs-type">Address</span> <span class="hljs-variable">workAddress</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span

Options

<span class="hljs-title class_">Address</span>(<span class="hljs-string">"Maple St."</span>, <span class="hljs-string">"67890"</span>, losAngeles);

    <span class="hljs-comment">// Create OfficeEmployee John with home and work addresses</span>
    <span class="hljs-type">OfficeEmployee</span> <span class="hljs-variable">john</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">OfficeEmployee</span>(<span class="hljs-string">"John"</span>, homeAddress, workAddress);

    employeeRepository.save(john);
}

<span class="hljs-keyword">public</span> OfficeEmployee <span class="hljs-title function_">getOfficeEmployee</span><span class="hljs-params">(Long id)</span> {
    <span class="hljs-keyword">return</span> (OfficeEmployee) employeeRepository.findById(id).orElse(<span class="hljs-literal">null</span>);
}

}</pre></div><h2 id="fcba">Controller</h2><p id="c2a6"><code><b>EmployeeController</b></code></p><div id="ff11"><pre><span class="hljs-keyword">import</span> org.springframework.beans.factory.<span class="hljs-keyword">annotation</span>.Autowired; <span class="hljs-keyword">import</span> org.springframework.web.bind.<span class="hljs-keyword">annotation</span>.GetMapping; <span class="hljs-keyword">import</span> org.springframework.web.bind.<span class="hljs-keyword">annotation</span>.RequestMapping; <span class="hljs-keyword">import</span> org.springframework.web.bind.<span class="hljs-keyword">annotation</span>.RestController;

<span class="hljs-meta">@RestController</span> <span class="hljs-meta">@RequestMapping(<span class="hljs-string">"/employees"</span>)</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">EmployeeController</span> {

<span class="hljs-meta">@Autowired</span>
<span class="hljs-keyword">private</span> EmployeeService employeeService;

<span class="hljs-meta">@GetMapping(<span class="hljs-string">"/create"</span>)</span>
<span class="hljs-keyword">public</span> String createEmployee() {
    employeeService.createEmployees();
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Employee created!"</span>;
}

<span class="hljs-meta">@GetMapping(<span class="hljs-string">"/officeEmployee"</span>)</span>
<span class="hljs-keyword">public</span> OfficeEmployee getOfficeEmployee() {
    <span class="hljs-keyword">return</span> employeeService.getOfficeEmployee(<span class="hljs-number">1L</span>);
}

}</pre></div><p id="0136"><b>Database Schema</b></p><p id="c15c"><code><b>city</b></code><b> Table</b></p><figure id="3b09"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*0Dpid0Qg9OOnLT_V06NtIw.png"><figcaption></figcaption></figure><p id="e2a2"><code><b>employee</b></code><b> Table</b></p><figure id="1f4a"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*jPo3fVcji6iEh1cwmk6qcg.png"><figcaption></figcaption></figure><p id="72a1"><code><b>office_employee</b></code><b> Table</b></p><figure id="e1ee"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*FaV-t-gYbxrzq4Ro31AZnw.png"><figcaption></figcaption></figure><h2 id="6f59">Sample Data and Output</h2><h2 id="157e">Insert data into City:</h2><div id="55dd"><pre><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> city (name) <span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'New York'</span>), (<span class="hljs-string">'Los Angeles'</span>);</pre></div><p id="58cf"><b>Insert data into <code>Employee</code> and <code>OfficeEmployee</code>:</b></p><div id="ef70"><pre><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> employee (name, home_street, home_zipCode, home_city_id) <span class="hljs-keyword">VALUES</span> (<span class="hljs-string">'John'</span>, <span class="hljs-string">'Elm St.'</span>, <span class="hljs-string">'12345'</span>, <span class="hljs-number">1</span>);

<span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> office_employee (id, work_street, work_zipCode, work_city_id) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">1</span>, <span class="hljs-string">'Maple St.'</span>, <span class="hljs-string">'67890'</span>, <span class="hljs-number">2</span>);</pre></div><h2 id="a03d">Output Example:</h2><ul><li><code>John</code> has a home address in <b>New York</b> (from <code>homeAddress.city</code>).</li><li><code>John</code> has a work address in <b>Los Angeles</b> (from <code>workAddress.city</code>).</li></ul><h2 id="2e78">Testing</h2><p id="05c2">You can use Postman or any other HTTP client to trigger the endpoints.</p><ol><li><b>Create the Employee and OfficeEmployee</b> <code>GET</code> request to: <code>http://localhost:8080/employees/create</code></li></ol><p id="0a7d"><b>Response:</b> <code>"Employee created!"</code></p><p id="6209"><b>2. Retrieve the OfficeEmployee with home and work addresses</b> <code>GET</code> request to: <code>http://localhost:8080/employees/officeEmployee</code></p><p id="b607">Sample Output (JSON):</p><div id="ba8f"><pre><span class="hljs-punctuation">{</span> <span class="hljs-attr">"id"</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">"name"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"John"</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">"homeAddress"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span> <span class="hljs-attr">"street"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"Elm St."</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">"zipCode"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"12345"</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">"city"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span> <span class="hljs-attr">"id"</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">"name"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"New York"</span> <span class="hljs-punctuation">}</span> <span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">"workAddress"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span> <span class="hljs-attr">"street"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"Maple St."</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">"zipCode"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"67890"</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">"city"</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span> <span class="hljs-attr">"id"</span><span class="hljs-punctuation">:</span> <span class="hljs-number">2</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">"name"</span><span class="hljs-punctuation">:</span> <span class="hljs-string">"Los Angeles"</span> <span class="hljs-punctuation">}</span> <span class="hljs-punctuation">}</span> <span class="hljs-punctuation">}</span></pre></div><h2 id="15a9">Database Schema</h2><p id="8aea">The schema created by Hibernate will include:</p><p id="c918"><b>1.<code>city</code> table:</b></p><ul><li><code>id</code> (primary key)</li><li><code>name</code></li></ul><p id="7e1f"><b>2.<code>employee</code> table (inherited by <code>OfficeEmployee</code>):</b></p><ul><li><code>id</code></li><li><code>name</code></li><li><code>home_street</code></li><li><code>home_zipCode</code></li><li><code>home_city_id</code></li></ul><p id="e229">3.<code><b>office_employee</b></code> table (extends <code>employee</code>):</p><ul><li><code>id</code></li><li><code>work_street</code></li><li><code>work_zipCode</code></li><li><code>work_city_id</code></li><li><code>@Embeddable</code> is used to embed the <code>Address</code> object in the <code>Employee</code> entity.</li><li><code>@AssociationOverride</code> is used in the <code>OfficeEmployee</code> to override the city relationship for the work address.</li><li>The entities are saved, and the output JSON shows how both the home and work addresses are associated with different cities.</li></ul><blockquote id="acac"><p><i>👏<b> If you found my articles useful, please consider giving it claps and sharing it with your friends and colleagues.</b></i></p></blockquote><p id="c1c0"><b>To read other topics</b></p><ul><li><a href="https://readmedium.com/using-hibernate-formula-in-spring-boot-to-compute-derived-fields-dynamically-21006573a82c"><b>@Formula Annotation in Spring Boot</b></a></li><li><a href="https://readmedium.com/transactional-annotation-in-spring-data-jpa-9f803d341289"><b>Mastering Transaction Propagation and Isolation in Spring Boot</b></a></li><li><a href="https://readmedium.com/mastering-git-and-github-integration-in-intellij-idea-a-complete-guide-to-version-control-7cf68cd7951a"><b>Git and GitHub Integration in IntelliJ IDEA</b></a></li><li><a href="https://readmedium.com/one-to-one-mapping-in-spring-boot-jpa-7b892f89a671"><b>One To One mapping in Spring Boot JPA</b></a></li><li><a href="https://readmedium.com/one-to-many-mapping-in-spring-boot-jpa-c3661451d4f2"><b>One To Many mapping in Spring Boot JPA</b></a></li><li><a href="https://readmedium.com/pessimistic-locking-in-jpa-with-spring-boot-267fafb6f62e"><b>Pessimistic Locking in JPA with Spring Boot</b></a></li><li><a href="https://readmedium.com/optimistic-locking-in-jpa-with-spring-boot-5afe19bcedbd"><b>Optimistic Locking in JPA with Spring Boot</b></a></li><li><a href="https://readmedium.com/optional-in-java-8-8b60f9957ccf"><b>Optional in Java 8</b></a></li></ul></article></body>

Hibernate @AssociationOverride for Customizing Entity Relationships in Spring Boot

The @AssociationOverride annotation in Spring Boot (JPA) allows you to override the mapping of a relationship (association) between entities in an embedded or inheritance context. It’s often used when you want to map an embedded entity's relationship to another entity differently in a specific class.

Use Case Scenario

Let’s say you have an Employee entity that contains an embedded Address entity. The Address entity has a relationship with a City entity. By default, the Employee entity would inherit the relationship of Address to City. But suppose in one particular case, you want to override that relationship in a subclass of Employee, or in a related entity. This is where @AssociationOverride comes into play.

GITHUB LINK

https://github.com/vinosubi/AssociationOverrideAnnotation.git

Example Scenario: Employee with a Work and Home Address

Entities:

  1. Employee has an embedded Address (home address by default).
  2. Address has a many-to-one relationship with a City.
  3. OfficeEmployee extends Employee and has a work address (overrides the city relationship of homeAddress).

1.City Entity

@Entity
public class City {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

    // Constructors, getters, setters
    public City() {}

    public City(String name) {
        this.name = name;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

2.Address Embeddable

@Embeddable
public class Address {
    private String street;
    private String zipCode;

    @ManyToOne
    @JoinColumn(name = "city_id")
    private City city;

    // Constructors, getters, setters
    public Address() {}

    public Address(String street, String zipCode, City city) {
        this.street = street;
        this.zipCode = zipCode;
        this.city = city;
    }

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    public String getZipCode() {
        return zipCode;
    }

    public void setZipCode(String zipCode) {
        this.zipCode = zipCode;
    }

    public City getCity() {
        return city;
    }

    public void setCity(City city) {
        this.city = city;
    }
}

@Embeddable

The @Embeddable annotation is used to mark a class whose instances are intended to be embedded in another entity. An embeddable class does not have its own separate identity (i.e., no primary key). Instead, its fields are part of the entity in which it is embedded.

Here, the Address class is marked with @Embeddable, meaning it can be embedded in another entity, such as Employee. The Address class contains attributes like street, zipCode, and a relationship to City. However, the Address entity will not have its own table, and its fields will be embedded in the table of the entity where it is used.

3.Employee Entity

@Entity
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

    @Embedded
    private Address homeAddress;

    // Constructors, getters, setters
    public Employee() {}

    public Employee(String name, Address homeAddress) {
        this.name = name;
        this.homeAddress = homeAddress;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Address getHomeAddress() {
        return homeAddress;
    }

    public void setHomeAddress(Address homeAddress) {
        this.homeAddress = homeAddress;
    }
}

@Embedded

The @Embedded annotation is used to specify that a field of an entity is an instance of an @Embeddable class, and the properties of that @Embeddable class should be included in the table of the containing entity.

In this case, the Employee entity contains the Address object as a field, and it's annotated with @Embedded. This means the homeAddress field in the Employee entity will embed the Address fields (e.g., street, zipCode, and city_id) into the employee table.

How It Works in the Database

When Address is embedded in Employee, it means that the Employee entity’s table will have columns corresponding to the fields of the Address entity, like street, zipCode, and city_id. These fields won't exist in a separate Address table, but rather as part of the employee table.

Key Points:

  • @Embeddable: Defines a class that can be embedded in another entity.
  • @Embedded: Embeds the fields of the @Embeddable class into the containing entity’s table.

OfficeEmployee Entity This entity extends Employee and overrides the relationship for work address using @AssociationOverride.

@Entity
@AssociationOverride(
    name = "homeAddress.city",
    joinColumns = @JoinColumn(name = "work_city_id") // Overrides the default "city_id"
)
public class OfficeEmployee extends Employee {

    @Embedded
    @AttributeOverrides({
        @AttributeOverride(name = "street", column = @Column(name = "work_street")),
        @AttributeOverride(name = "zipCode", column = @Column(name = "work_zipCode"))
    })
    private Address workAddress;

    // Constructors, getters, setters
    public OfficeEmployee() {}

    public OfficeEmployee(String name, Address homeAddress, Address workAddress) {
        super(name, homeAddress);
        this.workAddress = workAddress;
    }

    public Address getWorkAddress() {
        return workAddress;
    }

    public void setWorkAddress(Address workAddress) {
        this.workAddress = workAddress;
    }
}

@AssociationOverride

The @AssociationOverride annotation allows you to override the mapping of a relationship (association) in an embedded object or in an inheritance hierarchy. This is particularly useful when you have an @Embedded object with associations (such as @ManyToOne or @OneToMany), and you need to change the way the relationship is mapped in a subclass or another entity.

  • Purpose: In this case, we are overriding the city relationship in the homeAddress field (which is an embedded Address) for the OfficeEmployee entity. The @ManyToOne relationship for the city field in the homeAddress is overridden to use a different column (work_city_id) in the database.
  • Effect: This allows OfficeEmployee to use a different column for its city relationship compared to the Employee class, where the default column for homeAddress.city is home_city_id. In OfficeEmployee, we override this with work_city_id for the work address.

@AttributeOverrides

The @AttributeOverrides annotation allows you to override the column mappings for simple attributes in an embedded object. This is typically used to change the default column names that are automatically mapped based on the embedded object's fields.

  • Purpose: The @AttributeOverrides annotation is used to override the column names for the street and zipCode fields in the embedded Address object when it is mapped to workAddress.

Effect:

  • For workAddress.street, the column is named work_street instead of home_street (or whatever default column name would be used).
  • For workAddress.zipCode, the column is named work_zipCode instead of home_zipCode.

Repository

We need repositories to perform CRUD operations on the entities.

CityRepository

import org.springframework.data.jpa.repository.JpaRepository;

public interface CityRepository extends JpaRepository<City, Long> {}

EmployeeRepository

import org.springframework.data.jpa.repository.JpaRepository;

public interface CityRepository extends JpaRepository<City, Long> {}

Service Layer

EmployeeService

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;

@Service
public class EmployeeService {

    @Autowired
    private EmployeeRepository employeeRepository;

    @Autowired
    private CityRepository cityRepository;

    @Transactional
    public void createEmployees() {
        City newYork = new City("New York");
        City losAngeles = new City("Los Angeles");
        cityRepository.save(newYork);
        cityRepository.save(losAngeles);

        // Create home address for John
        Address homeAddress = new Address("Elm St.", "12345", newYork);

        // Create work address for John
        Address workAddress = new Address("Maple St.", "67890", losAngeles);

        // Create OfficeEmployee John with home and work addresses
        OfficeEmployee john = new OfficeEmployee("John", homeAddress, workAddress);

        employeeRepository.save(john);
    }

    public OfficeEmployee getOfficeEmployee(Long id) {
        return (OfficeEmployee) employeeRepository.findById(id).orElse(null);
    }
}

Controller

EmployeeController

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/employees")
public class EmployeeController {

    @Autowired
    private EmployeeService employeeService;

    @GetMapping("/create")
    public String createEmployee() {
        employeeService.createEmployees();
        return "Employee created!";
    }

    @GetMapping("/officeEmployee")
    public OfficeEmployee getOfficeEmployee() {
        return employeeService.getOfficeEmployee(1L);
    }
}

Database Schema

city Table

employee Table

office_employee Table

Sample Data and Output

Insert data into City:

INSERT INTO city (name) VALUES ('New York'), ('Los Angeles');

Insert data into Employee and OfficeEmployee:

INSERT INTO employee (name, home_street, home_zipCode, home_city_id) 
VALUES ('John', 'Elm St.', '12345', 1);

INSERT INTO office_employee (id, work_street, work_zipCode, work_city_id)
VALUES (1, 'Maple St.', '67890', 2);

Output Example:

  • John has a home address in New York (from homeAddress.city).
  • John has a work address in Los Angeles (from workAddress.city).

Testing

You can use Postman or any other HTTP client to trigger the endpoints.

  1. Create the Employee and OfficeEmployee GET request to: http://localhost:8080/employees/create

Response: "Employee created!"

2. Retrieve the OfficeEmployee with home and work addresses GET request to: http://localhost:8080/employees/officeEmployee

Sample Output (JSON):

{
    "id": 1,
    "name": "John",
    "homeAddress": {
        "street": "Elm St.",
        "zipCode": "12345",
        "city": {
            "id": 1,
            "name": "New York"
        }
    },
    "workAddress": {
        "street": "Maple St.",
        "zipCode": "67890",
        "city": {
            "id": 2,
            "name": "Los Angeles"
        }
    }
}

Database Schema

The schema created by Hibernate will include:

1.city table:

  • id (primary key)
  • name

2.employee table (inherited by OfficeEmployee):

  • id
  • name
  • home_street
  • home_zipCode
  • home_city_id

3.office_employee table (extends employee):

  • id
  • work_street
  • work_zipCode
  • work_city_id
  • @Embeddable is used to embed the Address object in the Employee entity.
  • @AssociationOverride is used in the OfficeEmployee to override the city relationship for the work address.
  • The entities are saved, and the output JSON shows how both the home and work addresses are associated with different cities.

👏 If you found my articles useful, please consider giving it claps and sharing it with your friends and colleagues.

To read other topics

Associationoverride
Jpa
Hibernate
Spring Boot
Entity Relationship Model
Recommended from ReadMedium