Apache Cayenne ORM 소개

1. 개요

Apache Cayenne은 Apache 라이선스에 따라 배포되는 오픈 소스 라이브러리로, 모델링 도구, 로컬 지속성 작업 및 원격 서비스를위한 ORM이라고하는 객체 관계형 매핑과 같은 기능을 제공합니다.

다음 섹션에서는 Apache Cayenne ORM을 사용하여 MySQL 데이터베이스와 상호 작용하는 방법을 살펴 봅니다.

2. Maven 종속성

시작하려면 다음 종속성을 추가하여 Apache Cayenne 및 MySQL 커넥터를 JDBC 드라이버로 함께 가져 와서 intro_cayenne 데이터베이스 에 액세스 하면 됩니다.

 org.apache.cayenne cayenne-server 4.0.M5   mysql mysql-connector-java 5.1.44 runtime 

데이터베이스 스키마와 Java 객체 사이의 다리 역할을하는 매핑 파일을 설계하거나 설정하는 데 사용할 Cayenne 모델러 플러그인을 구성 해 보겠습니다.

 org.apache.cayenne.plugins maven-cayenne-modeler-plugin 4.0.M5 

XML 매핑 파일을 손으로 만드는 대신 (드물게 만들어 짐) Cayenne 배포판과 함께 제공되는 매우 고급 도구 인 모델러를 사용하는 것이 좋습니다.

OS에 따라이 아카이브에서 다운로드하거나 Maven 플러그인으로 포함 된 교차 플랫폼 버전 (JAR)을 사용할 수 있습니다.

Maven Central 저장소는 최신 버전의 Apache Cayenne, 그의 모델러 및 MySQL 커넥터를 호스팅합니다.

다음으로, mvn install로 프로젝트를 빌드하고 mvn cayenne-modeler : run 명령을 사용하여 모델러 GUI를 시작 하여이 화면을 출력으로 가져옵니다.

3. 설정

Apache Cayenne이 올바른 로컬 데이터베이스를 찾도록 하려면 resources 디렉토리 에있는 cayenne-project.xml 파일에서 올바른 드라이버, URL 및 사용자로 구성 파일을 채우면됩니다 .

여기에서 확인할 수 있습니다.

  • 로컬 데이터베이스의 이름은 intro_cayenne입니다.
  • 아직 만들어지지 않았다면 Cayenne이 우리를 위해 할 것입니다.
  • 사용자 이름 root 와 암호 root를 사용하여 연결 합니다 (데이터베이스 관리 시스템에 등록 된 사용자에 따라 변경).

내부적 으로는 DataNodeDescriptor에 연결된 XML 리소스에서 JDBC 연결 정보를로드하는 역할을 하는 XMLPoolingDataSourceFactory 입니다.

이 라이브러리는 다양한 데이터베이스를 지원할 수 있으므로 이러한 매개 변수는 데이터베이스 관리 시스템 및 JDBC 드라이버와 관련이 있습니다.

이들 각각은이 상세 목록에서 사용할 수있는 어댑터를 가지고 있습니다. 버전 4.0에 대한 전체 문서는 아직 사용할 수 없으므로 여기에서 이전 버전을 참조합니다.

4. 매핑 및 데이터베이스 설계

4.1. 모델링

이제 “Open Project”를 클릭 하고 프로젝트의 리소스 폴더로 이동하여 cayenne-project.xml 파일을 선택 하면 모델러가 다음을 표시합니다.

여기 에서 기존 데이터베이스에서 매핑 구조를 만들 거나 수동으로 진행할 수 있습니다. 이 기사에서는 모델러와 기존 데이터베이스를 사용하여 Cayenne을 사용하고 작동 방식을 빠르게 파악합니다.

작성자가 많은 기사를 게시하거나 소유 할 수 있으므로 두 테이블에서 일대 다 관계 를 갖는 intro_cayenne 데이터베이스를 살펴 보겠습니다 .

  • 작성자 : ID (PK)이름
  • article : id (PK), title, contentauthor_id (FK)

이제 " Tools> Reengineer Database Schema " 로 이동하면 모든 매핑 구성이 자동으로 채워집니다. 프롬프트 화면에서 cayenne-project.xml 파일 에서 사용 가능한 데이터 소스 구성을 채우고 계속을 누르십시오.

다음 화면에서 다음과 같이 "Java 기본 유형 사용"을 선택해야합니다.

우리도 보장해야합니까? 넣어 com.baeldung.apachecayenne.persistent를 자바 패키지로 그리고 저장; XML 구성 파일이 Java 패키지와 일치하도록 defaultPackage 속성에 대해 업데이트되었음을 ​​확인할 수 있습니다 .

ObjEntity 에서 다음 이미지에 표시된대로 하위 클래스에 대한 패키지를 지정하고 "저장" 아이콘을 다시 클릭해야합니다.

이제 "Tools> Generate Classes" 메뉴에서 " Standard Persistent Objects "를 유형으로 선택 합니다. 과에 "클래스" 탭은 모든 클래스를 확인하고 충돌 "생성" .

소스 코드로 돌아가서 _Article.java_Author.java 에 대해 이야기하면서 지속적 개체가 성공적으로 생성되었는지 확인 합니다.

이러한 모든 구성은 리소스 폴더 에도있는 datamap.map.xml 파일에 저장됩니다 .

4.2. 매핑 구조

리소스 폴더에있는 생성 된 XML 매핑 파일은 Apache Cayenne과 관련된 몇 가지 고유 한 태그를 사용합니다.

  • DataNode() – 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() – it's a container of persistent entities with their relations
  • DbAttribute() – represents a column in a database table
  • DbEntity() – the model of a single database table or view, it can have DbAttributes and relationships
  • ObjEntity() – 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() – the model of a Java class that acts as a property of an ObjEntity, but corresponds to multiple columns in the database
  • Procedure() – to register stored procedure in the database
  • 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

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.

5.1. Creating an Object

Here, we just save an Author object and check later that there is only one record of this type in the database:

@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

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

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 authors = ObjectSelect .query(Author.class) .select(context); assertEquals(2, authors.size()); }

5.4. Updating an Object

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

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

The deletion of a saved object completely removes it from the database, thereafter we'll see null as the result of the query:

@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

SQLTemplate을 사용하여 테이블의 모든 레코드를 삭제할 수도 있습니다 . 여기서는 각 테스트가 시작되기 전에 항상 void 데이터베이스를 갖도록 각 테스트 메서드 후에이 작업을 수행합니다 .

@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. 결론

이 자습서에서는 Apache Cayenne ORM을 사용하여 일대 다 관계로 CRUD 작업을 수행하는 방법을 쉽게 시연하는 데 중점을 두었습니다 .

항상 그렇듯이이 기사의 소스 코드는 GitHub에서 찾을 수 있습니다.