предисловие
существуетMybatis
, есть мощный функциональный элементresultMap
. когда мы хотимJDBC ResultSets
Вы можете почувствовать его необычность при преобразовании данных в формате . Как говорится в официальном заявлении:
resultMap
элементMyBatis
самый важный и мощный элемент в Позволяет получить от 90%JDBC ResultSets
Он освобождает код извлечения данных и в некоторых случаях позволяет выполнять операции, которые JDBC не поддерживает. Фактически, при написании кода отображения для сложных операторов, таких как соединения,resultMap
Может заменить тысячи строк кода для достижения той же функции.ResultMap
Идея дизайна заключается в том, что нет необходимости настраивать явное сопоставление результатов для простых операторов, а нужно только описывать их отношения для более сложных операторов.
1. Картирование полей
существуетMybatis
, самый простой способ сопоставить результаты — использовать псевдонимы типов.typeAliases
обрабатывать.
Если вы хотите это сделать, первым шагом будет настройка пути к пакету класса сущностей:
mybatis.type-aliases-package=com.xxx.entity
Все классы по этому пути будут зарегистрированы вTYPE_ALIASES容器
. Когда мы указываем тип возвращаемого значения, мы можем напрямую использовать псевдоним.
Например, у нас естьUser
своего рода:
@Data
public class User {
private String id;
private String username;
private String password;
private String address;
private String email;
}
Если поля таблицы в базе данных совпадают сUser
Имя атрибута класса такое же, мы можем использоватьresultType
возвращаться.
<select id="getUsers" resultType="User">
SELECT
u.id,
u.username,
u.password,
u.address,
u.email
FROM
USER u
</select>
Конечно, в идеале это тот случай, когда имена свойств и полей полностью совпадают. Но на самом деле есть нестыковки, на этот раз нашиresultMap
собирается дебютировать.
еслиUser
Класс остался прежним, ноSQL
Заявление изменилось, т.id
изменился наuid
.
<select id="getUsers" resultType="User">
SELECT
u.id as uid,
u.username,
u.password,
u.address,
u.email
FROM
USER u
</select>
Тогда в результирующем наборе мы потеряемid
данные. Тогда мы можем определитьresultMap
, чтобы сопоставить различные поля.
<resultMap id="getUserByIdMap" type="User">
<result property="id" column="uid"></result>
</resultMap>
Затем ставим вышеуказанноеselect
в предложенииresultType
превратиться вresultMap="getUserByIdMap"
.
здесьcolumn
Соответствует имени столбца или псевдониму базы данных;property
Соответствует полям или атрибутам набора результатов.
ЭтоresultMap
Самое простое и основное использование: сопоставление полей.
Ниже мы рассмотрим, как применяются другие теги.
имя элемента | описывать |
---|---|
constructor | Используется для ввода результата в конструктор при создании экземпляра класса. |
association | связать объект |
collection | Связать несколько объектов |
Во-вторых, метод построения.
Если вы хотите ввести результат в конструктор, вы можете использоватьconstructor
элемент.
Например, нашUser
Класс добавляет конструктор:
public User(String id, String name) {
this.id = id+"--------";
this.username = name+"--------";
}
нам надоresultMap
определено вconstructor
элемент:
<resultMap id="getUserByIdMap" type="User">
<constructor>
<idArg column="id" name="id" javaType="string"></idArg>
<arg column="username" name="name" javaType="string"></arg>
</constructor>
</resultMap>
в,column
Представляет имя или псевдоним поля базы данных;name
имя параметра в конструкторе;javaType
Указывается тип параметра.
Как вы понимаете, после указания такого конструктора наш результирующий набор имеет видid和username
свойства изменятся.
{
"id": "1001--------",
"username": "后羿--------",
"password": "123456",
"address": "北京市海淀区",
"email": "510273027@qq.com"
}
3. Ассоциация
В реальном бизнесе наши пользователи обычно играют определенную роль. затем вUser
Класс обычно представлен классом сущностей.
@Data
public class User {
//省略用户属性...
//角色信息
private Role role;
}
Когда мы запрашиваем пользователя, если мы также хотим увидеть информацию о его роли, мы напишем оператор запроса следующим образом:
<select id="getUserById" resultType="User">
SELECT
u.id,
u.username,
u.password,
u.address,
u.email,
r.id as 'role_id',
r.name as 'role_name'
FROM
USER u
LEFT JOIN user_roles ur ON u.id = ur.user_id
LEFT JOIN role r ON r.id = ur.role_id
where u.id=#{id}
</select>
Как и выше, необходимо запросить информацию об одном пользователе и роли пользователя. Но здесь мы не можем использоватьresultType=User
возвращаться.
после всего,User
В классе только одинRole
объект, неrole_id和role_name
Свойства поля.
Итак, мы собираемся использоватьassociation
связать их.
<resultMap id="userMap" type="User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="password" column="password"></result>
<result property="address" column="address"></result>
<result property="email" column="email"></result>
<association property="role" javaType="Role">
<id property="id" column="role_id"></id>
<result property="name" column="role_name"></result>
</association>
</resultMap>
Наконец, мы можем отобразить информацию о роли в одном фрагменте:
{
"id": "1001",
"username": "后羿",
"password": "123456",
"address": "北京市海淀区",
"email": "510273027@qq.com",
"role": {
"id": "3",
"name": "射手"
}
}
Фактически, если вы определите, что связанная информация一对一
, есть более простой способ заменитьassociation
, мы в этой статье第五部分-自动填充关联对象
Давайте посмотрим, как он это делает.
4. Коллекция
1. Вложенное отображение результатов наборов
Сверху мы видим пользователя后羿
, его роль射手
; но в большинстве случаев у каждого из нас не может быть только одной роли. Поэтому нам нужноUser
Тип атрибута роли в классе изменен наList
.
@Data
public class User {
//省略用户属性...
//角色信息
private List<Role> roles;
}
Теперь он становится пользователем, соответствующим нескольким ролям, так что это не простоassociation
.
так какassociation
иметь дело с有一个
Ассоциация типов; и вот мы有多个
ассоциация типов, поэтому вам нужно использоватьcollection
Атрибуты.
наш общийresultMap
станет следующим:
<resultMap id="userMap" type="User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="password" column="password"></result>
<result property="address" column="address"></result>
<result property="email" column="email"></result>
<collection property="roles" ofType="Role">
<id property="id" column="role_id"></id>
<result property="name" column="role_name"></result>
</collection>
</resultMap>
Таким образом, даже если у вас несколько символов, они будут отображаться правильно:
{
"id": "1003",
"username": "貂蝉",
"password": "123456",
"address": "北京市东城区",
"email": "510273027@qq.com",
"roles": [
{
"id": "1",
"name": "中单"
},
{
"id": "2",
"name": "打野"
}
]
}
2. Вложенный запрос Select для коллекций
В большинстве бизнес-систем у нас будет таблица меню, такая как следующая:Menu
поверхность:
id | name | url | parent_id |
---|---|---|---|
1 | Управление системой | 0 | |
1001 | Управление пользователями | /user | 1 |
1002 | управление ролями | /role | 1 |
1003 | Управление подразделением | /employer | 1 |
2 | Мониторинг платформы | 0 | |
2001 | Мониторинг системы | /system/monitor | 2 |
2002 | Мониторинг данных | /data/monitor | 2 |
Здесь мы делим меню на два уровня. Когда мы возвращаем меню на фронтенд, его тоже нужно градировать, и вывести эти 7 кусков данных по горизонтали невозможно. Итак, вот нашMenu
Класс сущности выглядит следующим образом:
@Data
public class Menu {
private String id;
private String name;
private String url;
private String parent_id;
private List<Menu> childMenu;
}
Здесь используется меню первого уровня, которое содержит список меню второго уровня.childMenu
Представлять.
SQL
заявление, если нетparent_id
Свойства поля, сначала проверяем все меню первого уровня:
<select id="getMenus" resultMap="menusMap">
SELECT
m.id,
m.name,
m.url,
m.parent_id
FROM
m_menu m
where 1=1
<choose>
<when test="parent_id!=null">
and m.parent_id = #{parent_id}
</when>
<otherwise>
and m.parent_id = '0'
</otherwise>
</choose>
</select>
В этом операторе запроса без передачи каких-либо параметров мы получим данные двух меню первого уровня.
Итак, как запросить всю информацию о меню и отобразить ее по уровням, когда этот метод вызывается только один раз?
ПосмотримmenusMap
Определение:
<resultMap id="menusMap" type="Menu">
<id property="id" column="id"></id>
<result property="name" column="name"></result>
<result property="url" column="url"></result>
<result property="m_desc" column="m_desc"></result>
<result property="parent_id" column="parent_id"></result>
<collection property="childMenu" ofType="Menu" select="getMenus" column="{parent_id=id}"></collection>
</resultMap>
Сконцентрируйсяcollection
элемент:
property="childMenu"
Соответствует списку подменю в меню;
ofType="Menu"
Соответствует типу возвращаемых данных;
select="getMenus"
указанныйSELECT
идентификатор заявления;
column="{parent_id=id}"
является выражением для параметра.
этоcollection
Общий смысл можно понять так:
пройти черезgetMenus
этоSELECT语句
чтобы получить меню первого уровняchildMenu
результат свойства; в вышеприведенномSELECT语句
, вам нужно пройтиparent_id
параметр; значением этого параметра является значение в меню первого уровняid
.
Таким образом, мы можем получить всю информацию о меню, которая была оценена.
[
{
"id": "1",
"name": "系统管理",
"parent_id": "0",
"childMenu": [
{
"id": "1001",
"name": "用户管理",
"url": "/user",
"parent_id": "1"
},
{
"id": "1002",
"name": "角色管理",
"url": "/role",
"parent_id": "1"
},
{
"id": "1003",
"name": "单位管理",
"url": "/employer",
"parent_id": "1"
}
]
},
{
"id": "2",
"name": "平台监控",
"parent_id": "0",
"childMenu": [
{
"id": "2001",
"name": "系统监控",
"url": "/system/monitor",
"parent_id": "2"
},
{
"id": "2002",
"name": "数据监控",
"url": "/data/monitor",
"parent_id": "2"
}
]
}
]
5. Автоматически заполнять связанные объекты
мы знаем, что вMybatis
При анализе возвращаемого значения.
Первый шаг — получить тип возвращаемого значения, получитьClass
объект, затем получите конструктор, установите доступность и верните экземпляр, затем снова оберните его какMetaObject
объект.
из базы данныхrs
После получения результата он вызоветMetaObject.setValue(String name, Object value)
для заполнения объекта.
В процессе, что интересно,.
отделить этоname
Атрибуты.
еслиname
свойство содержит.符号
, найти.符号
Предыдущее имя свойства, рассматривайте его как объект сущности.
Возможно, описание автора здесь недостаточно интуитивное, давайте рассмотрим пример.
в этой статье第三部分
, у нас есть一个用户对应一个角色
пример.
в,User
Класс определяется следующим образом:
@Data
public class User {
//省略用户属性...
//角色信息
private Role role;
}
Здесь нам не нужно определятьresultMap
, вернуться напрямуюresultType=User
Вот и все. Но нужноrole
Измените псевдоним информации, суть.符号
<select id="getUserList" resultType="User">
SELECT
u.id,
u.username,
u.password,
u.address,
u.email,
r.id as 'role.id',
r.name as 'role.name'
FROM
USER u
LEFT JOIN user_roles ur ON u.id = ur.user_id
LEFT JOIN role r ON r.id = ur.role_id
</select>
Таким образом, вMybatis
решитьсяrole.id
собственность, с.符号
После разделения выяснилось, чтоrole
Псевдоним соответствуетRole
объект, он будет инициализирован первымRole
объект и присвоить значениеid
Атрибуты.
Соответствующий код показан на рисунке: