Apache Cayenne中的高级查询
1.概述
之前 ,我们专注于如何开始使用 Apache Cayenne。
在本文中,我们将介绍如何使用 ORM 编写简单和高级查询。
2. 设置
该设置类似于上一篇文章中使用的设置。
此外,在每次测试之前,我们会保存三位作者,并在最后删除他们:
- Paul Xavier
- pAuL Smith
- Vicky Sarra
3. ObjectSelect
让我们从简单的开始,看看我们如何获取名字中包含“Paul”的所有作者:
@Test
public void whenContainsObjS_thenWeGetOneRecord() {
List<Author> authors = ObjectSelect.query(Author.class)
.where(Author.NAME.contains("Paul"))
.select(context);
assertEquals(authors.size(), 1);
}
接下来,让我们看看如何在 Author’s name 列上应用不区分大小写的 LIKE 类型的查询:
@Test
void whenLikeObjS_thenWeGetTwoAuthors() {
List<Author> authors = ObjectSelect.query(Author.class)
.where(Author.NAME.likeIgnoreCase("Paul%"))
.select(context);
assertEquals(authors.size(), 2);
}
接下来,*endsWith()*表达式将只返回一条记录,因为只有一位作者具有匹配的姓名:
@Test
void whenEndsWithObjS_thenWeGetOrderedAuthors() {
List<Author> authors = ObjectSelect.query(Author.class)
.where(Author.NAME.endsWith("Sarra"))
.select(context);
Author firstAuthor = authors.get(0);
assertEquals(authors.size(), 1);
assertEquals(firstAuthor.getName(), "Vicky Sarra");
}
更复杂的是查询名称在列表中的作者:
@Test
void whenInObjS_thenWeGetAuthors() {
List names = Arrays.asList(
"Paul Xavier", "pAuL Smith", "Vicky Sarra");
List<Author> authors = ObjectSelect.query(Author.class)
.where(Author.NAME.in(names))
.select(context);
assertEquals(authors.size(), 3);
}
nin是相反的,这里只有“Vicky”会出现在结果中:
@Test
void whenNinObjS_thenWeGetAuthors() {
List names = Arrays.asList(
"Paul Xavier", "pAuL Smith");
List<Author> authors = ObjectSelect.query(Author.class)
.where(Author.NAME.nin(names))
.select(context);
Author author = authors.get(0);
assertEquals(authors.size(), 1);
assertEquals(author.getName(), "Vicky Sarra");
}
请注意,以下两个代码是相同的,因为它们都将创建具有相同参数的相同类型的表达式:
Expression qualifier = ExpressionFactory
.containsIgnoreCaseExp(Author.NAME.getName(), "Paul");
Author.NAME.containsIgnoreCase("Paul");
以下是*Expression * 和ExpressionFactory 类中一些可用表达式的列表:
- likeExp : 用于构建 LIKE 表达式
- likeIgnoreCaseExp:用于构建 LIKE_IGNORE_CASE 表达式
- containsExp : LIKE 查询的表达式,其模式匹配字符串中的任何位置
- containsIgnoreCaseExp :与containsExp相同,但使用不区分大小写的方法
- startsWithExp:模式应该匹配字符串的开头
- startsWithIgnoreCaseExp:类似于startsWithExp但使用不区分大小写的方法
- endsWithExp : 匹配字符串结尾的表达式
- endsWithIgnoreCaseExp:使用不区分大小写的方法匹配字符串结尾的表达式
- expTrue : 布尔true表达式
- expFalse : 用于布尔false表达式
- andExp:用于用and运算符链接两个表达式
- orExp : 使用or运算符链接两个表达式
4. SelectQuery
它是用户应用程序中使用最广泛的查询类型。SelectQuery描述了一个简单而强大的 API,其行为类似于 SQL 语法,但仍然使用 Java 对象和方法,然后使用构建器模式来构造更复杂的表达式。
在这里,我们谈论的是一种表达式语言,其中我们使用Expression(用于构建表达式)又名限定符和Ordering(用于对结果排序)类构建查询,这些类接下来由 ORM 转换为原生 SQL。
为了看到这一点,我们汇总了一些测试,在实践中展示了如何构建一些表达式和对数据进行排序。
让我们应用一个 LIKE 查询来获取名称为“Paul”的作者:
@Test
void whenLikeSltQry_thenWeGetOneAuthor() {
Expression qualifier
= ExpressionFactory.likeExp(Author.NAME.getName(), "Paul%");
SelectQuery query
= new SelectQuery(Author.class, qualifier);
List<Author> authorsTwo = context.performQuery(query);
assertEquals(authorsTwo.size(), 1);
}
这意味着如果您不向查询 ( SelectQuery ) 提供任何表达式,则结果将是 Author 表的所有记录。
可以使用containsIgnoreCaseExp表达式执行类似的查询,以获取姓名中包含 Paul 的所有作者,无论字母的大小写如何:
@Test
void whenCtnsIgnorCaseSltQry_thenWeGetTwoAuthors() {
Expression qualifier = ExpressionFactory
.containsIgnoreCaseExp(Author.NAME.getName(), "Paul");
SelectQuery query
= new SelectQuery(Author.class, qualifier);
List<Author> authors = context.performQuery(query);
assertEquals(authors.size(), 2);
}
类似地,让我们以不区分大小写的方式(containsIgnoreCaseExp )获取名称包含“Paul”的作者,并以字母 h结尾的名称(endsWithExp ):
@Test
void whenCtnsIgnorCaseEndsWSltQry_thenWeGetTwoAuthors() {
Expression qualifier = ExpressionFactory
.containsIgnoreCaseExp(Author.NAME.getName(), "Paul")
.andExp(ExpressionFactory
.endsWithExp(Author.NAME.getName(), "h"));
SelectQuery query = new SelectQuery(
Author.class, qualifier);
List<Author> authors = context.performQuery(query);
Author author = authors.get(0);
assertEquals(authors.size(), 1);
assertEquals(author.getName(), "pAuL Smith");
}
可以使用Ordering类执行升序:
@Test
void whenAscOrdering_thenWeGetOrderedAuthors() {
SelectQuery query = new SelectQuery(Author.class);
query.addOrdering(Author.NAME.asc());
List<Author> authors = query.select(context);
Author firstAuthor = authors.get(0);
assertEquals(authors.size(), 3);
assertEquals(firstAuthor.getName(), "Paul Xavier");
}
这里不使用query.addOrdering(Author.NAME.asc()),我们也可以只使用SortOrder类来获取升序:
query.addOrdering(Author.NAME.getName(), SortOrder.ASCENDING);
相对有降序排列:
@Test
void whenDescOrderingSltQry_thenWeGetOrderedAuthors() {
SelectQuery query = new SelectQuery(Author.class);
query.addOrdering(Author.NAME.desc());
List<Author> authors = query.select(context);
Author firstAuthor = authors.get(0);
assertEquals(authors.size(), 3);
assertEquals(firstAuthor.getName(), "pAuL Smith");
}
正如我们在前面的示例中看到的 - 设置此排序的另一种方法是:
query.addOrdering(Author.NAME.getName(), SortOrder.DESCENDING);
5. SQLTemplate
SQLTemplate也是我们可以与 Cayenne 一起使用以不使用对象样式查询的一种替代方法。
使用SQLTemplate构建查询与使用某些参数编写本机 SQL 语句直接相关。让我们实现一些简单的例子。
以下是我们在每次测试后删除所有作者的方法:
@After
void deleteAllAuthors() {
SQLTemplate deleteAuthors = new SQLTemplate(
Author.class, "delete from author");
context.performGenericQuery(deleteAuthors);
}
要查找所有记录的作者,我们只需要应用 SQL 查询 select * from Author ,我们将直接看到结果是正确的,因为我们恰好保存了三个作者:
@Test
void givenAuthors_whenFindAllSQLTmplt_thenWeGetThreeAuthors() {
SQLTemplate select = new SQLTemplate(
Author.class, "select * from Author");
List<Author> authors = context.performQuery(select);
assertEquals(authors.size(), 3);
}
接下来,让我们获取名为“Vicky Sarra”的作者:
@Test
void givenAuthors_whenFindByNameSQLTmplt_thenWeGetOneAuthor() {
SQLTemplate select = new SQLTemplate(
Author.class, "select * from Author where name = 'Vicky Sarra'");
List<Author> authors = context.performQuery(select);
Author author = authors.get(0);
assertEquals(authors.size(), 1);
assertEquals(author.getName(), "Vicky Sarra");
}
6. EJBQLQuery
接下来,让我们通过EJBQLQuery 查询数据,它是作为在 Cayenne 中采用 Java Persistence API 的实验的一部分而创建的。
在这里,查询以参数化的对象样式应用;让我们看一些实际的例子。
首先,所有已保存作者的搜索将如下所示:
@Test
void givenAuthors_whenFindAllEJBQL_thenWeGetThreeAuthors() {
EJBQLQuery query = new EJBQLQuery("select a FROM Author a");
List<Author> authors = context.performQuery(query);
assertEquals(authors.size(), 3);
}
让我们再次使用名称“Vicky Sarra”搜索作者,但现在使用EJBQLQuery:
@Test
void givenAuthors_whenFindByNameEJBQL_thenWeGetOneAuthor() {
EJBQLQuery query = new EJBQLQuery(
"select a FROM Author a WHERE a.name = 'Vicky Sarra'");
List<Author> authors = context.performQuery(query);
Author author = authors.get(0);
assertEquals(authors.size(), 1);
assertEquals(author.getName(), "Vicky Sarra");
}
一个更好的例子是更新作者:
@Test
void whenUpdadingByNameEJBQL_thenWeGetTheUpdatedAuthor() {
EJBQLQuery query = new EJBQLQuery(
"UPDATE Author AS a SET a.name "
+ "= 'Vicky Edison' WHERE a.name = 'Vicky Sarra'");
QueryResponse queryResponse = context.performGenericQuery(query);
EJBQLQuery queryUpdatedAuthor = new EJBQLQuery(
"select a FROM Author a WHERE a.name = 'Vicky Edison'");
List<Author> authors = context.performQuery(queryUpdatedAuthor);
Author author = authors.get(0);
assertNotNull(author);
}
7. SQLExec
SQLExec也是从 Cayenne M4 版本引入的一个新的 Fluent 查询 API。
一个简单的插入看起来像这样:
@Test
void whenInsertingSQLExec_thenWeGetNewAuthor() {
int inserted = SQLExec
.query("INSERT INTO Author (name) VALUES ('Blogdemo')")
.update(context);
assertEquals(inserted, 1);
}
接下来,我们可以根据作者的姓名更新作者:
@Test
void whenUpdatingSQLExec_thenItsUpdated() {
int updated = SQLExec.query(
"UPDATE Author SET name = 'Blogdemo' "
+ "WHERE name = 'Vicky Sarra'")
.update(context);
assertEquals(updated, 1);
}
我们可以从文档 中获得更多细节。