DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • Useful System Table Queries in Relational Databases
  • How to Restore a Transaction Log Backup in SQL Server
  • How to Attach SQL Database Without a Transaction Log File
  • A Deep Dive into Apache Doris Indexes

Trending

  • Next-Gen IoT Performance Depends on Advanced Power Management ICs
  • Optimizing Software Performance for High-Impact Asset Management Systems
  • Mastering Advanced Traffic Management in Multi-Cloud Kubernetes: Scaling With Multiple Istio Ingress Gateways
  • Assessing Bias in AI Chatbot Responses
  1. DZone
  2. Data Engineering
  3. Databases
  4. IBatis (MyBatis): Discriminator Column Example – Inheritance Mapping Tutorial

IBatis (MyBatis): Discriminator Column Example – Inheritance Mapping Tutorial

By 
Loiane Groner user avatar
Loiane Groner
·
Mar. 22, 11 · Tutorial
Likes (0)
Comment
Save
Tweet
Share
33.7K Views

Join the DZone community and get the full member experience.

Join For Free

This tutorial will walk you through how to setup iBatis (MyBatis) in a simple Java project and will present an example using a discriminator column, in another words it is a inheritance mapping tutorial.

Pre-Requisites

For this tutorial I am using:

IDE: Eclipse (you can use your favorite one)
DataBase: MySQL
Libs/jars: Mybatis, MySQL conector and JUnit (for testing)

This is how your project should look like:

Sample Database

Please run the script into your database before getting started with the project implementation. You will find the script (with dummy data) inside the sql folder.

1 – POJOs – Beans

I represented the beans here with a UML model, but you can download the complete source code in the end of this article.

As you can see on the Data Modeling Diagram and the UML diagram above, we have a class Employee and two subclasses: Developer and Manager. The goal of this tutorial is to retrieve all the Employees from the database, but these employees can be an instance of Developer or Manager, and we are going to use a discriminator column to see which class we are going to instanciate.

2 – Employee Mapper – XML

Sometimes a single database query might return result sets of many different (but hopefully somewhat related) data types. The discriminator element was designed to deal with this situation, and others, including class inheritance hierarchies. The discriminator is pretty simple to understand, as it behaves much like a switch statement in Java.

A discriminator definition specifies column and javaType attributes. The column is where MyBatis will look for the value to compare. The javaType is required to ensure the proper kind of equality test is performed (although String would probably work for almost any situation).

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapper  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"    "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="Employee">     <resultMap id="resultEmployee" type="Employee">        <result property="id"/>        <result property="name"/>        <discriminator javaType="int" column="employee_type">            <case value="1" resultMap="resultManager"/>            <case value="2" resultMap="resultDeveloper"/>        </discriminator>    </resultMap>     <resultMap id="resultManager" type="Manager">        <result property="managerId" column="manager_id" />        <result property="info" column="info" />    </resultMap>          <resultMap id="resultDeveloper" type="Developer">        <result property="developerId" column="developer_id" />        <result property="project" column="product" />    </resultMap>      <select id="getAllEmployees" resultMap="resultEmployee">        SELECT            id, name, employee_type,            manager_id, info,            developer_id, product        FROM employee E            left join manager M on M.employee_id = E.id            left join developer D on D.employee_id = E.id    </select></mapper>

In this example, MyBatis would retrieve each record from the result set and compare its employee type value. If it matches any of the discriminator cases, then it will use the resultMap specified by the case.

This is done exclusively, so in other words, the rest of the resultMap is ignored (unless it is extended, which we talk about in a second). If none of the cases match, then MyBatis simply uses the resultMap as defined outside of the discriminator block.

So, if the managerResult was declared as follows:

<resultMap id="resultManager" type="Manager">    <result property="managerId" column="manager_id" />    <result property="info" column="info" /></resultMap

Then ONLY the managerId and info properties would be loaded. This is done to allow completely independent groups of discriminator cases, even ones that have no relationship to the parent resultMap. In this case we do of course know that there’s a relationship between manager and employee, as a Manager is-a Employee.

Therefore, we want the rest of the properties loaded too. One simple change to the resultMap and we’re set to go.

<resultMap id="resultManager" type="Manager" extends="resultEmployee">    <result property="managerId" column="manager_id" />    <result property="info" column="info" /></resultMap>

Now all of the properties from both the managerResult and developerResult will be loaded.

Once again though, some may find this external definition of maps somewhat tedious. Thereforethere’s an alternative syntax for those that prefer a more concise mapping style. For example:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapper  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"    "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="Employee">     <resultMap id="resultEmployee" type="Employee">        <result property="id"/>        <result property="name"/>        <discriminator javaType="int" column="employee_type">            <case value="1" resultType="Manager">                <result property="managerId" column="manager_id" />                <result property="info" column="info" />            </case>            <case value="2" resultType="Developer">                <result property="developerId" column="developer_id" />                <result property="project" column="product" />            </case>        </discriminator>    </resultMap>      <select id="getAllEmployees" resultMap="resultEmployee">        SELECT            id, name, employee_type,            manager_id, info,            developer_id, product        FROM employee E            left join manager M on M.employee_id = E.id            left join developer D on D.employee_id = E.id    </select></mapper>

Remember that these are all Result Maps, and if you don’t specify any results at all, then MyBatis willautomatically match up columns and properties for you. So most of these examples are more verbosethan they really need to be. That said, most databases are kind of complex and it’s unlikely that we’ll beable to depend on that for all cases.

3 - Employee Mapper – Annotations

We did the configuration in XML, now let’s try to use annotations to do the same thing we did using XML.

This is the code for EmployeeMapper.java:

package com.loiane.data; import java.util.List; import org.apache.ibatis.annotations.Case;import org.apache.ibatis.annotations.Result;import org.apache.ibatis.annotations.Select;import org.apache.ibatis.annotations.TypeDiscriminator; import com.loiane.model.Developer;import com.loiane.model.Employee;import com.loiane.model.Manager; public interface EmployeeMapper {     final String SELECT_EMPLOYEE = "SELECT id, name, employee_type, manager_id, info, developer_id, product " +            "FROM employee E left join manager M on M.employee_id = E.id " +            "left join developer D on D.employee_id = E.id ";     /**     * Returns the list of all Employee instances from the database.     * @return the list of all Employee instances from the database.     */    @Select(SELECT_EMPLOYEE)    @TypeDiscriminator(column = "employee_type",        cases = {            @Case (value="1", type = Manager.class,                results={                    @Result(property="managerId", column="manager_id"),                    @Result(property="info"),            }),            @Case (value="2", type = Developer.class,                results={                    @Result(property="developerId", column="developer_id"),                    @Result(property="project", column="product"),            })    })    List<Employee> getAllEmployeesAnnotation();}

If you are reading this blog lately, you are already familiar with the @Select and @Result annotations. So let’s skip it. Let’s talk about the @TypeDiscriminator and @Case annotations.

@TypeDiscriminator

A group of value cases that can be used to determine the result mapping to perform.

Attributes: column, javaType, jdbcType, typeHandler, cases. The cases attribute is an array of Cases.

@Case

A single case of a value and its corresponding mappings.

Attributes: value, type, results.

The results attribute is an array of Results, thus this Case Annotation is similar to an actual ResultMap, specified by the Results annotation below.

In this example:

We set the column atribute for @TypeDiscriminator to determine which column MyBatis will look for the value to compare. And we set an array of @Case.

For each @Case we set the value, so if the column matches the value, MyBatis will instanciate a object of type we set and we also set an array of @Result to match column with class atribute.

Note one thing: using XML we set the id and name properties. We did not set these properties using annotations. It is not necessary, because the column matches the atribute name. But if you need to set, it is going to look like this:

@Select(SELECT_EMPLOYEE)@Results(value = {    @Result(property="id"),    @Result(property="name")})@TypeDiscriminator(column = "employee_type",    cases = {        @Case (value="1", type = Manager.class,            results={                @Result(property="managerId", column="manager_id"),                @Result(property="info"),        }),        @Case (value="2", type = Developer.class,            results={                @Result(property="developerId", column="developer_id"),                @Result(property="project", column="product"),        })})List<Employee> getAllEmployeesAnnotation();

4 – EmployeeDAO

In the DAO, we have two methods: the first one will call the select statement from the XML and the second one will call the annotation method. Both returns the same result.

package com.loiane.dao; import java.util.List; import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory; import com.loiane.data.EmployeeMapper;import com.loiane.model.Employee; public class EmployeeDAO {     /**     * Returns the list of all Employee instances from the database.     * @return the list of all Employee instances from the database.     */    @SuppressWarnings("unchecked")    public List<Employee> selectAll(){         SqlSessionFactory sqlSessionFactory = MyBatisConnectionFactory.getSqlSessionFactory();        SqlSession session = sqlSessionFactory.openSession();         try {            List<Employee> list = session.selectList("Employee.getAllEmployees");            return list;        } finally {            session.close();        }    }     /**     * Returns the list of all Employee instances from the database.     * @return the list of all Employee instances from the database.     */    public List<Employee> selectAllUsingAnnotations(){         SqlSessionFactory sqlSessionFactory = MyBatisConnectionFactory.getSqlSessionFactory();        SqlSession session = sqlSessionFactory.openSession();         try {            EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);             List<Employee> list = mapper.getAllEmployeesAnnotation();            return list;        } finally {            session.close();        }    }}

The output if you call one of these methods and print:

Employee ID = 1 Name = Kate Manager ID = 1 Info = info KateEmployee ID = 2 Name = Josh Developer ID = 1 Project = webEmployee ID = 3 Name = Peter Developer ID = 2 Project = desktopEmployee ID = 4 Name = James Manager ID = 2 Info = info JamesEmployee ID = 5 Name = Susan Developer ID = 3 Project = web

Download

If you want to download the complete sample project, you can get it from my GitHub account: https://github.com/loiane/ibatis-discriminator

If you want to download the zip file of the project, just click on download:

There are more articles about iBatis to come. Stay tooned!

 

From http://loianegroner.com/2011/03/ibatis-mybatis-discriminator-column-example-inheritance-mapping-tutorial/

sql Database Discriminator MyBatis Inheritance (object-oriented programming) Annotation

Opinions expressed by DZone contributors are their own.

Related

  • Useful System Table Queries in Relational Databases
  • How to Restore a Transaction Log Backup in SQL Server
  • How to Attach SQL Database Without a Transaction Log File
  • A Deep Dive into Apache Doris Indexes

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!