1. Overview
1.概述
Apache Cayenne is an open-source library, distributed under the Apache license, providing features like a modeling tool, object-relational mapping aka ORM for local persistence operations and remoting services.
Apache Cayenne是一个开源库,在Apache许可下发布,提供建模工具、对象关系映射(又称ORM)的本地持久化操作和远程服务等功能。
In the following sections, we’ll see how to interact with a MySQL database using Apache Cayenne ORM.
在下面的章节中,我们将看到如何使用Apache Cayenne ORM与MySQL数据库互动。
2. Maven Dependencies
2.Maven的依赖性
To start, we just need to add the following dependencies to bring up Apache Cayenne and MySQL connector the JDBC driver together to access our intro_cayenne database:
开始时,我们只需要添加以下依赖项,使Apache Cayenne和MySQL连接器的JDBC驱动程序一起访问我们的intro_cayenne数据库。
<dependency>
<groupId>org.apache.cayenne</groupId>
<artifactId>cayenne-server</artifactId>
<version>4.0.M5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.44</version>
<scope>runtime</scope>
</dependency>
Let’s configure Cayenne modeler plugin that will be used for designing or setting our mapping file that acts as a bridge between the database schema and the Java object:
让我们来配置Cayenne modeler插件,它将被用来设计或设置我们的映射文件,作为数据库模式和Java对象之间的一个桥梁。
<plugin>
<groupId>org.apache.cayenne.plugins</groupId>
<artifactId>maven-cayenne-modeler-plugin</artifactId>
<version>4.0.M5</version>
</plugin>
Instead of building XML mapping file by hand (made rarely), it’s recommended to use the modeler which is a pretty advanced tool that comes with the Cayenne distribution.
与其手工建立XML映射文件(很少做),建议使用建模器,这是一个相当先进的工具,随Cayenne发行版一起提供。
It’s available for download from this archive depending on your OS or just use the cross-platform version (JAR) included as a Maven plugin up there.
根据你的操作系统,可以从这个archive下载,或者直接使用上面作为Maven插件的跨平台版本(JAR)。
The Maven Central repository host the latest versions of Apache Cayenne, his modeler, and MySQL Connector.
Maven Central资源库承载了Apache Cayenne、his modeler和MySQL Connector的最新版本。
Next, let’s build our project with the mvn install and launch the modeler GUI with the command mvn cayenne-modeler:run to get as output this screen:
接下来,让我们用mvn install构建我们的项目,用mvn cayenne-modeler:run命令启动建模器GUI,得到这个屏幕输出。
3. Setup
3.设置
To make Apache Cayenne look up the correct local database, we just need to fill his configuration file with the right driver, URL, and a user in the file cayenne-project.xml located in the resources directory:
为了让Apache Cayenne查找正确的本地数据库,我们只需要在位于resources目录下的cayenne-project.xml文件中,用正确的驱动程序、URL和一个用户来填充他的配置文件。
<?xml version="1.0" encoding="utf-8"?>
<domain project-version="9">
<node name="datanode"
factory
="org.apache.cayenne.configuration.server.XMLPoolingDataSourceFactory"
schema-update-strategy
="org.apache.cayenne.access.dbsync.CreateIfNoSchemaStrategy">
<data-source>
<driver value="com.mysql.jdbc.Driver"/>
<url value
="jdbc:mysql://localhost:3306/intro_cayenne;create=true"/>
<connectionPool min="1" max="1"/>
<login userName="root" password="root"/>
</data-source>
</node>
</domain>
Here we can see that:
在这里我们可以看到。
- The local database is named intro_cayenne
- If it’s not yet created, Cayenne will do it for us
- We’ll connect using the username root and password root (change it according to the users registered in your database management system)
Internally, it’s the XMLPoolingDataSourceFactory responsible for loading JDBC connection information from an XML resource associated to the DataNodeDescriptor.
在内部,它是XMLPoolingDataSourceFactory,负责从与DataNodeDescriptor相关的XML资源加载JDBC连接信息。
Be aware that these parameters are relative to the database management system and a JDBC driver because this library can support many different databases.
请注意,这些参数是相对于数据库管理系统和JDBC驱动程序而言的,因为这个库可以支持许多不同的数据库。
Each of them has an adapter available in this detailed list. Notice, that the full documentation for version 4.0 is not yet available, so we refer to the previous version here.
在这个详细的列表中,每一个都有一个适配器可用。请注意,4.0版本的完整文档还没有出来,所以我们在这里参考以前的版本。
4. Mapping & Database Design
4.制图与数据库设计
4.1. Modeling
4.1.建模
Let’s now click on the “Open Project”, navigate to the project’s resources folder and chose the file cayenne-project.xml, the modeler will show this:
现在让我们点击“打开项目”,导航到项目的资源文件夹,选择文件cayenne-project.xml,建模器将显示这个。
Here, we’ve got the choice to either create our mapping structure from an existing database or to proceed manually. This article will handle the one using the modeler and existing database to get into Cayenne and know quickly how it works.
在这里,我们可以选择从现有的数据库中创建我们的映射结构 或者手动进行。本文将处理使用建模器和现有数据库来进入Cayenne并快速了解它的工作方式。
Let’s take a look at our intro_cayenne database which has a one-to-many relationship across two tables, as an author can publish or own many articles:
让我们看看我们的intro_cayenne数据库,它在两个表中有一个一对多的关系,因为一个作者可以发表或拥有许多文章。
- author: id (PK) and name
- article: id (PK), title, content, and author_id(FK)
Now let’s go to “Tools > Reengineer Database Schema“, and we’ll have all our mapping configs filled automatically. On the prompt screen just fill the data source configuration available up there in the cayenne-project.xml file and hit continue:
现在让我们进入”Tools > Reengineer Database Schema“,我们将自动填充所有的映射配置。在提示屏幕上,只要填写cayenne-project.xml文件中可用的数据源配置,然后点击继续。
On the next screen, we need to check “Use Java primitive types” as follows:
在下一个屏幕上,我们需要选中 “使用Java原始类型”,如下所示。
We need also to ensure to put com.baeldung.apachecayenne.persistent as Java package and save it; we’ll see that the XML configuration file has been updated for its defaultPackage property to match the Java package:
我们还需要确保将com.baeldung.apachecayenne.persistent作为Java包并保存;我们将看到XML配置文件中的defaultPackage属性已经被更新,以匹配Java包。
In each ObjEntity we must specify the package for subclasses as shown in the following image and click the “save” icon again:
在每个ObjEntity中,我们必须为子类指定包,如下图所示,并再次点击“保存”图标。
Now on “Tools > Generate Classes” menu, select “Standard Persistent Objects” as the type; and on the “Classes” tab check all classes and hit “generate”.
现在在“Tools > Generate Classes”菜单上,选择”Standard Persistent Objects“作为类型;并在“Classes”标签上选中所有类,然后点击“generate”。
Let’s go back to the source code to see that our persistent objects have been generated successfully, talking about _Article.java and _Author.java.
让我们回到源代码中,看看我们的持久化对象已经成功生成,谈论_Article.java和_Author.java。
Note that all these configurations are saved in the file datamap.map.xml also located in the resources folder.
注意,所有这些配置都保存在datamap.map.xml文件中,也位于resources文件夹中。
4.2. Mapping Structure
4.2.绘图结构
The generated XML mapping file presents in the resource folder is using some unique tags relative to Apache Cayenne:
生成的XML映射文件呈现在资源文件夹中,使用了一些相对于Apache Cayenne的独特标签。
- DataNode(<node>) – the model of the database, its contents all information necessary to get connected to a database (the name of the database, the driver and the user credentials)
- DataMap(<data-map>) – it’s a container of persistent entities with their relations
- DbAttribute(<db-attribute>) – represents a column in a database table
- DbEntity(<db-entity>) – the model of a single database table or view, it can have DbAttributes and relationships
- ObjEntity(<obj-entity>) – the model of a single persistent java class; made of ObjAttributes that correspond to entity class properties and ObjRelationships that are properties that have a type of another entity
- Embeddable(<embeddable>) – the model of a Java class that acts as a property of an ObjEntity, but corresponds to multiple columns in the database
- Procedure(<procedure>) – to register stored procedure in the database
- Query(<query>) – the model of a query, used to mapped query in configuration file without forget that we can also do it in the code
Here are the full details.
以下是完整的细节。
5. Cayenne API
5.Cayenne API
The only remaining step is to use the Cayenne API to do our database operations using generated classes, knowing that subclassing our persistent classes is just a best practice used for customizing the model later.
剩下的唯一步骤是使用Cayenne API,使用生成的类来完成我们的数据库操作,要知道,对我们的持久化类进行子类化只是一种最佳做法,用于以后定制模型。
5.1. Creating an Object
5.1.创建一个对象
Here, we just save an Author object and check later that there is only one record of this type in the database:
在这里,我们只是保存了一个Author对象,并在之后检查数据库中是否只有一条这种类型的记录。
@Test
public void whenInsert_thenWeGetOneRecordInTheDatabase() {
Author author = context.newObject(Author.class);
author.setName("Paul");
context.commitChanges();
long records = ObjectSelect.dataRowQuery(Author.class)
.selectCount(context);
assertEquals(1, records);
}
5.2. Reading an Object
5.2.读取一个对象
After saving an Author, we just pick it among others via a simple query by a particular property:
在保存了一个作者之后,我们只需通过一个简单的查询,通过一个特定的属性在其他作者中挑选。
@Test
public void whenInsert_andQueryByFirstName_thenWeGetTheAuthor() {
Author author = context.newObject(Author.class);
author.setName("Paul");
context.commitChanges();
Author expectedAuthor = ObjectSelect.query(Author.class)
.where(Author.NAME.eq("Paul"))
.selectOne(context);
assertEquals("Paul", expectedAuthor.getName());
}
5.3. Retrieving All Records of a Class
5.3.检索一个类别的所有记录
We’re going to save two authors and retrieve a collection of author objects to check that there are just these two saved:
我们要保存两个作者,并检索一个作者对象的集合,以检查是否只有这两个被保存。
@Test
public void whenInsert_andQueryAll_thenWeGetTwoAuthors() {
Author firstAuthor = context.newObject(Author.class);
firstAuthor.setName("Paul");
Author secondAuthor = context.newObject(Author.class);
secondAuthor.setName("Ludovic");
context.commitChanges();
List<Author> authors = ObjectSelect
.query(Author.class)
.select(context);
assertEquals(2, authors.size());
}
5.4. Updating an Object
5.4.更新一个对象
The updating process is easy too, but we need first to have the desired object before modifying its properties and applying it to the database:
更新过程也很简单,但我们首先需要有一个想要的对象,然后再修改它的属性并应用到数据库中。
@Test
public void whenUpdating_thenWeGetAnUpatedeAuthor() {
Author author = context.newObject(Author.class);
author.setName("Paul");
context.commitChanges();
Author expectedAuthor = ObjectSelect.query(Author.class)
.where(Author.NAME.eq("Paul"))
.selectOne(context);
expectedAuthor.setName("Garcia");
context.commitChanges();
assertEquals(author.getName(), expectedAuthor.getName());
}
5.5. Attaching an Object
5.5.附加一个对象
We can assign an article to an author:
我们可以把一篇文章分配给一个作者。
@Test
public void whenAttachingToArticle_thenTheRelationIsMade() {
Author author = context.newObject(Author.class);
author.setName("Paul");
Article article = context.newObject(Article.class);
article.setTitle("My post title");
article.setContent("The content");
article.setAuthor(author);
context.commitChanges();
Author expectedAuthor = ObjectSelect.query(Author.class)
.where(Author.NAME.eq("Smith"))
.selectOne(context);
Article expectedArticle = (expectedAuthor.getArticles()).get(0);
assertEquals(article.getTitle(), expectedArticle.getTitle());
}
5.6. Deleting an Object
5.6.删除一个对象
The deletion of a saved object completely removes it from the database, thereafter we’ll see null as the result of the query:
删除一个已保存的对象会将其从数据库中完全删除,此后我们会看到null作为查询的结果。
@Test
public void whenDeleting_thenWeLostHisDetails() {
Author author = context.newObject(Author.class);
author.setName("Paul");
context.commitChanges();
Author savedAuthor = ObjectSelect.query(Author.class)
.where(Author.NAME.eq("Paul"))
.selectOne(context);
if(savedAuthor != null) {
context.deleteObjects(author);
context.commitChanges();
}
Author expectedAuthor = ObjectSelect.query(Author.class)
.where(Author.NAME.eq("Paul"))
.selectOne(context);
assertNull(expectedAuthor);
}
5.7. Delete All Records of a Class
5.7.删除某类的所有记录
It’s also possible to drop all the records of a table usingSQLTemplate, here we do this after each test method to always have a void database before each test is launched:
也可以使用SQLTemplate删除一个表的所有记录,这里我们在每个测试方法之后做这个,以便在每个测试启动之前总是有一个无效的数据库:。
@After
public void deleteAllRecords() {
SQLTemplate deleteArticles = new SQLTemplate(
Article.class, "delete from article");
SQLTemplate deleteAuthors = new SQLTemplate(
Author.class, "delete from author");
context.performGenericQuery(deleteArticles);
context.performGenericQuery(deleteAuthors);
}
6. Conclusion
6.结论
In this tutorial, we focused on using Apache Cayenne ORM to easily demonstrate how to do CRUD operations with a one-to-many relationship.
在本教程中,我们着重于使用Apache Cayenne ORM来轻松演示如何用一对多关系进行CRUD操作。
As always, the source code for this article can be found over on GitHub.
像往常一样,本文的源代码可以在GitHub上找到over。