id
не является первичным ключом в wrapTreeTable
.Примечание: Данная ситуация встречается редко и не влияет на нормальное использование.
convertType
.SqlToyDaoSupport
, чтобы преобразовать публичные методы, добавленные позже, в защищённые (protected
), чтобы избежать вызова методов родительского класса при работе с пользовательским DAO и возникновения помех.Улучшение возможностей выполнения запросов между базами данных с поддержкой SQL ID=DIALECT_ID или ID_DIALECT. Выполнение запроса происходит в порядке приоритета ID, объединённого с текущим диалектом базы данных, таким образом, если используется MySQL, то сначала проверяются MYSQL_ID и ID_MYSQL. В случае отсутствия подходящего запроса выполняется запрос, соответствующий ID, что позволяет дополнительно улучшить возможности работы с несколькими базами данных.
Добавление макроса @LOOP(LOOP_PARAM, LOOP_CONTENT, LINK_SIGN) для встраивания SQL, что обеспечивает гибкость в составлении динамических SQL в крайних случаях.
<sql id="qstart_loop_sql">
<value>
<![CDATA[
SELECT ORDER_ID
@LOOP(:FIELDS,",:FIELDS[I]")
FROM SQLTOY_DEVICE_ORDER T
WHERE #[T.ORDER_ID = :ORDER_ID]
#[@IF(SIZE(:STAFF_IDS) > 0) AND (@LOOP(:STAFF_IDS, " T.STAFF_ID = ':STAFF_IDS[I]' ", " OR ", "1", "100"))]
#[@BLANK(:START_DATES)
AND ( @LOOP(:START_DATES,
" T.TRANS_DATE BETWEEN STR_TO_DATE(':START_DATES[I]', '%Y-%m-%d')
AND STR_TO_DATE(':END_DATES[I]', '%Y-%m-%d') ",
" OR "))]
]]>
</value>
</sql>
Улучшение функциональности @IF(), предоставляющее возможность получения размера массива и проверки наличия конкретного значения внутри него, как @IF(SIZE(:STATUS_ARY) > 0) или @IF(:STATUS_ARY INCLUDE 1).
Усовершенствование функциональности saveOrUpdate, которое различает случаи полной уникальности ключей и отсутствия ключей, а также продолжает выполнение операции saveAllIgnoreExist при успешном выполнении.
Оптимизация вывода логов выполнения, чтобы они были представлены в виде единого отчёта.
Дальнейшее усовершенствование TranslateManager для упрощения вторичного расширения, что делает его удобным для разработчиков для реализации почти реального времени управления кэшированием.
В CollectionUtil добавлено сортирование списка дерева, что облегчает обработку результатов запросов к таблицам со структурой дерева, позволяя прямое отображение страницы! (Различие между версией 4.16.1 и 4.16.0)
link
<!-- Пример использования link, если требуется пагинация, используйте @fast() для выборки 10 записей перед связыванием, в результате вернется 10 записей -->
<sql id="qstart_link_case">
<value>
<![CDATA[
SELECT t.ORGAN_ID, t.ORGAN_ID AS ORGAN_NAME, t.STAFF_NAME, t.SEX_TYPE, t.SEX_TYPE AS sexTypeName
FROM sqltoy_staff_info t
ORDER BY t.ORGAN_ID
]]>
</value>
<!-- Объединение нескольких колонок, можно сначала перевести, а затем объединить -->
<link id-column="ORGAN_ID" columns="STAFF_NAME,sexTypeName" sign="," />
<translate cache="dictKeyName" columns="sexTypeName" cache-type="SEX_TYPE"/>
<translate cache="organIdName" columns="ORGAN_NAME"/>
</sql>
saveOrUpdate
для PostgreSQL 9.4 (версия 9.4 не поддерживает режим insert table AS T1
с использованием псевдонима, поэтому он был удалён)loadBySql
и load(entity)
, чтобы избежать ошибок при определении типа объекта в крайнем случае с двойными фигурными скобками new VO(){{setId("")}}
:param
в SQL, чтобы адаптироваться к сценариям запросов PostgreSQL с JSON форматом ::jsonb
, который может влиять на условия параметраJSONB
и других в quickvo
translateManager
(ранее требовалось вызывать ещё один уровень), что позволяет пользователям легко расширять возможности для близкого к реальному времени обновления кэша1 Для запросов открытого типа используется режим передачи параметров Map<String, Object>
, что удобно для разработки проектов с отчётами.
2 Улучшение формата вывода логов.
3 Оптимизация обработки functionConvert
для PostgreSQL group_concat
.
<dependency>
<groupId>com.sagframe</groupId>
<artifactId>sagacity-sqltoy-starter</artifactId>
<version>4.15.7</version>
</dependency>
EntityQuery.create().select(StaffInfoVO.select().staffId().staffCode().staffName().organId().sexType())
// Поддержка динамических условий
.where("#[STATUS=?] #[and STAFF_NAME like ?]").orderByDesc("entryDate").values(1, "Чень")
// Отключение blankToNull
//.blankNotNull()
);
Большое спасибо пользователю ccc за обратную связь, которая помогла своевременно исправить указанные проблемы в версии 4.15.3!
конкретные поля.
findEntity
.loadByIds
для прямого массового загрузки объектов по коллекции идентификаторов.quickvo
для предоставления цепочечной выборки полей в методе findEntity
.PaginationModel<StaffInfoVO> result = sqlToyLazyDao.findEntity(StaffInfoVO.class, new PaginationModel(),
// Поддерживает три способа указания полей:
// 1. Одним строковым значением для нескольких полей
// EntityQuery.create().select("staffId,staffCode, staffName, organId, sexType")
// 2. Предоставление полей в виде массива
// EntityQuery.create().select("staffId", "staffCode", "staffName", "organId", "sexType")
// 3. Цепочка методов для указания полей
EntityQuery.create().select(StaffInfoVO.select().staffId().staffCode().staffName().organId().sexType())
// Поддержка динамических условий
.where("STATUS=1 #[and STAFF_NAME like :staffName]").orderByDesc("entryDate")
.values(new StaffInfoVO().setStaffName("Чжэн")).filters(new ParamsFilter("staffName").rlike())
// Поддержка кэширования
.translates(new Translate("organIdName").setKeyColumn("organId").setColumn("organName"))
// Поддержка оптимизации пагинации
.pageOptimize(new PageOptimize().aliveSeconds(120)));
// parallQuery предназначен для выполнения запросов (не используйте его в процессах транзакций), sqltoy предоставляет мощные методы, но правильное использование зависит от пользователя
/**
* @TODO Параллельный запрос и возврат одномерного списка, количество объектов результатов равно количеству запросов, paramNames и paramValues — это объединение условий всех SQL-запросов
* @param parallQueryList
* @param paramNames
* @param paramValues
*/
public <T> List<QueryResult<T>> parallQuery(List<ParallQuery> parallQueryList, String[] paramNames,
Object[] paramValues);
// Используется параллельный запрос для одновременного выполнения двух SQL-запросов, условия параметров являются объединением обоих запросов
String[] paramNames = new String[] {"userId", "defaultRoles", "deployId", "authObjType"};
Object[] paramValues = new Object[] {userId, defaultRoles, GlobalConstants.DEPLOY_ID,
SagacityConstants.TempAuthObjType.GROUP};
List<QueryResult<TreeModel>> list = super.parallQuery(
Arrays.asList(ParallQuery.create().sql("webframe_searchAllModuleMenus").resultType(TreeModel.class),
ParallQuery.create().sql("webframe_searchAllUserReports").resultType(TreeModel.class)),
paramNames, paramValues);
@if(:statusAry include 1)
незаконных вопросительных знаков
SELECT 'x?' AS col1, name FROM table WHERE status = ?
хранимых процедур
Благодарим активных участников сети за ценные отзывы, благодаря которым SQLToy становится всё лучше!
контексте "DTO" и "POJO" остаются без изменения, так как это специфические термины в программировании. DTO — объект передачи данных POJO — простой старый объект Java
SqlToyCRUDService
, SqlToyLazyDao
и SqlToySupportDao
./**
* Реализует копирование значений свойств между DTO и POJO. В случае, если названия полей различаются,
* можно использовать аннотацию @SqlToyFieldAlias в полях DTO для корректной обработки.
* @param <T>
* @param source Исходный объект для конвертации
* @param resultType Тип результата конвертации
* @return Конвертированный объект типа T
* @throws Exception
*/
public <T extends Serializable> T convertType(Serializable source, Class<T> resultType) throws Exception;
/**
* Реализует копирование значений свойств между коллекциями DTO и POJO. В случае, если названия полей различаются,
* можно использовать аннотацию @SqlToyFieldAlias в полях DTO для корректной обработки.
* @param <T>
* @param sourceList Исходная коллекция для конвертации
* @param resultType Тип результата конвертации
* @return Коллекция конвертированных объектов типа T
*/
public <T extends Serializable> List<T> convertType(List<Serializable> sourceList, Class<T> resultType)
throws Exception;
Translate
, добавлены внутренние классы для сокращения количества методов get
при вызовах от разработчиков, что помогает избежать путаницы при выборе нужных методов.(рекомендовано обновление)
@Test
public void findEntityByVO() {
List<StaffInfoVO> staffVOs = sqlToyLazyDao.findEntity(StaffInfoVO.class,
EntityQuery.create().where("#[staffId=:staffId]#[and staffName like :staffName] #[ and status=:status]")
.values(new StaffInfoVO().setStatus(-1).setStaffName("陈").setStaffId("S0005"))
.filters(new ParamsFilter("status").eq(-1))
.filters(new ParamsFilter("staffName").rlike())
.filters(new ParamsFilter("staffId").primary())
.secureMask(MaskType.ADDRESS, "address")
.secureMask(MaskType.TEL, "telNo"));
System.err.println(JSON.toJSONString(staffVOs));
}
Улучшен подход реализации метода isUnique
за счет снижения количества запросов count
, что повысило производительность!
Исправлены проблемы, возникающие при выполнении операций cascade update
в различных базах данных (MySQL, PostgreSQL, SQLite) из-за багов этих систем, связанных с непустыми полями. Теперь используется двухэтапный режим взаимодействия для решения этой проблемы.
См. исправления ошибок в версии sqltoy 4.2.6
Ошибка MySQL при on duplicate key update, когда поле в базе данных имеет значение not null: SQL error [1048] [23000]: Column 'NAME' cannot be null
Большое спасибо всем пользователям, предоставившим обратную связь!
связной операции.
отслеживание операциями эксплуатации.
sql_id
как уникальный идентификатор для удобства отслеживания запросов через базу данных.Пример с MySQL: В начале каждого SQL-запроса добавляется id
, что позволяет операционному персоналу быстро находить конкретные SQL-запросы в логах базы данных.
/* id=qstart_order_search */ SELECT ORDER_ID, DEVICE_TYPE,
Благодарю пользователя cmd за это предложение!
Устранил ошибку в динамическом установлении кэша перевода в коде, используя пример использования в проекте quickstart, см. StaffInfoDao
public PaginationModel<StaffInfoVO> findStaff(PaginationModel<StaffInfoVO> pageModel, StaffInfoVO staffInfoVO) {
// SQL можно написать прямо в коде, сложные SQL рекомендуется определять в xml
// В случае одиночной таблицы entity запроса поля SQL могут быть записаны как свойства Java-класса
// Одиночная таблица обычно используется для внутренних запросов интерфейсов, а для страниц редко требуется одиночная таблица (кроме случаев ETL-агрегации)
String sql = "#[staffName like :staffName]#[and createTime>=:beginDate]#[and createTime<=:endDate]";
return findEntity(StaffInfoVO.class, pageModel, EntityQuery.create().where(sql).values(staffInfoVO)
// Кэширование словарей обязательно должно быть установлено cacheType
// Нужно установить keyColumn для создания select keyColumn as column режима
.translates(new Translate("dictKeyName").setColumn("sexTypeName").setCacheType("SEX_TYPE")
.setKeyColumn("sexType"))
.translates(new Translate("organIdName").setColumn("organName").setKeyColumn("organId")));
}
Обеспечил стандартизацию класса инструмента FileUtil
, чтобы предоставить некоторые необходимые инструменты для помощи в тестировании.
Объединил методы update(Entity)
, update(Entity, String[] forceUpdateProps)
и аналогичные методы с использованием update(Entity, String... forceUpdateProps)
, что позволило уменьшить часть избыточного кода.
Спасибо за обращение по этому вопросу: компания Zhike Software!
сервисами)
<sql id="rpt_datasql1">
<s:sharding-datasource strategy="skylineStrategy" />
<s:translate cache="staffIdName" columns="CREATE_BY" uncached-template=""/>
<s:filters>
<s:eq params="*" value="-1"/>
</s:filters>
<s:value><![CDATA[
]]></s:value>
</sql>
Улучшить QuickVo для поддержки типов данных nvarchar и money по умолчанию.
Оптимизировать метод loadAll для выполнения запросов по частям, чтобы избежать ошибки при превышении количества параметров IN в SQL более чем 1000.