1. 概要

ORMLite は、Javaアプリケーション用の軽量ORMライブラリです。 これは、他のORMフレームワークの複雑さとオーバーヘッドを追加することなく、最も一般的なユースケース用のORMツールの標準機能を提供します。

主な機能は次のとおりです。

  • Javaアノテーションを使用したエンティティクラスの定義
  • 拡張可能なDAOクラス
  • 複雑なクエリを作成するためのQueryBuilderクラス
  • データベーステーブルを作成および削除するために生成されたクラス
  • トランザクションのサポート
  • 実体関連のサポート

次のセクションでは、ライブラリを設定し、エンティティクラスを定義し、ライブラリを使用してデータベースで操作を実行する方法を見ていきます。

2. Mavenの依存関係

ORMLiteの使用を開始するには、ormlite-jdbc依存関係をpom.xmlに追加する必要があります。

<dependency>
    <groupId>com.j256.ormlite</groupId>
    <artifactId>ormlite-jdbc</artifactId>
    <version>5.0</version>
</dependency>

デフォルトでは、これによりh2依存関係も発生します。 この例では、 H2 インメモリデータベースを使用するため、別のJDBCドライバーは必要ありません。

別のデータベースを使用する場合は、対応する依存関係も必要になります。

3. エンティティクラスの定義

ORMLiteを使用して永続化するためにモデルクラスを設定するには、次の2つの主要な注釈を使用できます。

  • エンティティクラスの@DatabaseTable
  • プロパティの@DatabaseField

nameフィールドと主キーでもあるlibraryIdフィールドを使用してLibraryエンティティを定義することから始めましょう。

@DatabaseTable(tableName = "libraries")
public class Library {	
 
    @DatabaseField(generatedId = true)
    private long libraryId;

    @DatabaseField(canBeNull = false)
    private String name;

    public Library() {
    }
    
    // standard getters, setters
}

@DatabaseTable アノテーションには、デフォルトのクラス名に依存したくない場合にテーブルの名前を指定するオプションのtableName属性があります。

データベーステーブルの列として保持するすべてのフィールドに対して、@DatabaseFieldアノテーションを追加する必要があります。

テーブルの主キーとして機能するプロパティは、 id GeneratedId 、またはgenerateSequence属性のいずれかでマークできます。 この例では、generatedId = true 属性を選択して、主キーが自動的にインクリメントされるようにします。

また、クラスには、少なくともpackage-scopeの可視性を備えた引数のないコンストラクターが必要であることに注意してください。

フィールドの構成に使用できるその他の使い慣れた属性は、 columnName dataType defaultValue canBeNull unique[ X167X]。

3.1. JPAアノテーションの使用

ORMLite固有のアノテーションに加えて、JPAスタイルのアノテーションを使用してエンティティを定義することもできます

JPA標準アノテーションを使用する前に定義したLibraryエンティティに相当するものは次のとおりです。

@Entity
public class LibraryJPA {
 
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long libraryId;

    @Column
    private String name;
    
    // standard getters, setters
}

ORMLiteはこれらのアノテーションを認識しますが、それらを使用するにはjavax.persistence-api依存関係を追加する必要があります。

サポートされているJPAアノテーションの完全なリストは、@ Entity @Id、 @Column、 @GeneratedValue、です。 @ OneToOne @ ManyToOne、 @ JoinColumn 、@バージョン

4. ConnectionSource

定義されたオブジェクトを操作するには、ConnectionSourceを設定する必要があります。

このために、単一の接続を作成する JdbcConnectionSource クラス、または単純なプールされた接続ソースを表すJdbcPooledConnectionSourceを使用できます。

JdbcPooledConnectionSource connectionSource 
  = new JdbcPooledConnectionSource("jdbc:h2:mem:myDb");

// work with the connectionSource

connectionSource.close();

DataSourceConnectionSource オブジェクトでラップすることにより、パフォーマンスが向上した他の外部データソースも使用できます。

5. TableUtilsクラス

ConnectionSource に基づいて、 TableUtilsクラスの静的メソッドを使用して、データベーススキーマで操作を実行できます。

  • createTable() –エンティティクラス定義またはDatabaseTableConfigオブジェクトに基づいてテーブルを作成します
  • createTableIfNotExists() –前のメソッドと同様ですが、テーブルが存在しない場合にのみテーブルを作成する点が異なります。 これは、それをサポートするデータベースでのみ機能します
  • dropTable() –テーブルを削除します
  • clearTable ()–テーブルからデータを削除します

TableUtilsを使用してLibraryクラスのテーブルを作成する方法を見てみましょう。

TableUtils.createTableIfNotExists(connectionSource, Library.class);

6. DAOオブジェクト

ORMLiteには、CRUD機能を使用してDAOオブジェクトを作成できるDaoManagerクラスが含まれています。

Dao<Library, Long> libraryDao 
  = DaoManager.createDao(connectionSource, Library.class);

DaoManager は、 createDao()、の後続の呼び出しごとにクラスを再生成しませんが、代わりにパフォーマンスを向上させるためにクラスを再利用します。

次に、Libraryオブジェクトに対してCRUD操作を実行できます。

Library library = new Library();
library.setName("My Library");
libraryDao.create(library);
        
Library result = libraryDao.queryForId(1L);
        
library.setName("My Other Library");
libraryDao.update(library);
        
libraryDao.delete(library);

DAO は、すべてのレコードをループできるイテレーターでもあります。

libraryDao.forEach(lib -> {
    System.out.println(lib.getName());
});

ただし、ORMLiteは、ループが最後まで進んだ場合にのみ、基になるSQLステートメントを閉じます。 例外またはreturnステートメントにより、コードでリソースリークが発生する可能性があります。

そのため、ORMLiteのドキュメントでは、イテレータを直接使用することを推奨しています。

try (CloseableWrappedIterable<Library> wrappedIterable 
  = libraryDao.getWrappedIterable()) {
    wrappedIterable.forEach(lib -> {
        System.out.println(lib.getName());
    });
 }

このようにして、 try-with-resourcesまたはfinally ブロックを使用してイテレーターを閉じ、リソースリークを回避できます。

6.1. カスタムDAOクラス

提供されているDAOオブジェクトの動作を拡張する場合は、Daoタイプを拡張する新しいインターフェイスを作成できます。

public interface LibraryDao extends Dao<Library, Long> {
    public List<Library> findByName(String name) throws SQLException;
}

次に、このインターフェイスを実装し、BaseDaoImplクラスを拡張するクラスを追加しましょう。

public class LibraryDaoImpl extends BaseDaoImpl<Library, Long> 
  implements LibraryDao {
    public LibraryDaoImpl(ConnectionSource connectionSource) throws SQLException {
        super(connectionSource, Library.class);
    }

    @Override
    public List<Library> findByName(String name) throws SQLException {
        return super.queryForEq("name", name);
    }
}

このフォームのコンストラクターが必要であることに注意してください。

最後に、カスタム DAO、を使用するには、クラス名をLibraryクラス定義に追加する必要があります。

@DatabaseTable(tableName = "libraries", daoClass = LibraryDaoImpl.class)
public class Library { 
    // ...
}

これにより、 DaoManager を使用して、カスタムクラスのインスタンスを作成できます。

LibraryDao customLibraryDao 
  = DaoManager.createDao(connectionSource, Library.class);

次に、標準の DAO クラスのすべてのメソッドと、カスタムメソッドを使用できます。

Library library = new Library();
library.setName("My Library");

customLibraryDao.create(library);
assertEquals(
  1, customLibraryDao.findByName("My Library").size());

7. 実体関連の定義

ORMLiteは、「外部」オブジェクトまたはコレクションの概念を使用して、永続性のためのエンティティ間の関係を定義します。

各タイプのフィールドを定義する方法を見てみましょう。

7.1. 異物フィールド

@DatabaseFieldで注釈が付けられたフィールドでforeign= true 属性を使用することにより、2つのエンティティクラス間に一方向の1対1の関係を作成できます。 このフィールドは、データベースにも保持されているタイプである必要があります。

まず、Addressという新しいエンティティクラスを定義しましょう。

@DatabaseTable(tableName="addresses")
public class Address {
    @DatabaseField(generatedId = true)
    private long addressId;

    @DatabaseField(canBeNull = false)
    private String addressLine;
    
    // standard getters, setters 
}

次に、タイプAddressのフィールドをforeignとしてマークされたLibraryクラスに追加できます。

@DatabaseTable(tableName = "libraries")
public class Library {      
    //...

    @DatabaseField(foreign=true, foreignAutoCreate = true, 
      foreignAutoRefresh = true)
    private Address address;

    // standard getters, setters
}

@DatabaseFieldアノテーションにさらに2つの属性foreignAutoCreateforeignAutoRefreshを追加したことに注意してください。どちらもtrueに設定されています。

forumAutoCreate = true 属性は、Libraryオブジェクトをaddressフィールドで保存すると、そのidがあれば外部オブジェクトも保存されることを意味します。 はnullではなく、generatedId =true属性を持っています。

forumAutoCreateをデフォルト値であるfalseに設定した場合、外部オブジェクトを参照する Library オブジェクトを保存する前に、外部オブジェクトを明示的に永続化する必要があります。 。

同様に、 forumAutoRefresh = true 属性は、 Library オブジェクトを取得するときに、関連する外部オブジェクトも取得されることを指定します。 それ以外の場合は、手動で更新する必要があります。

Addressフィールドを持つ新しいLibraryオブジェクトを追加し、libraryDaoを呼び出して両方を永続化してみましょう。

Library library = new Library();
library.setName("My Library");
library.setAddress(new Address("Main Street nr 20"));

Dao<Library, Long> libraryDao 
  = DaoManager.createDao(connectionSource, Library.class);
libraryDao.create(library);

次に、 addressDao を呼び出して、Addressも保存されていることを確認できます。

Dao<Address, Long> addressDao 
  = DaoManager.createDao(connectionSource, Address.class);
assertEquals(1, 
  addressDao.queryForEq("addressLine", "Main Street nr 20")
  .size());

7.2. 外国のコレクション

のためにたくさんの関係の側面では、タイプを使用できます ForeignCollection またコレクションとともに @ForeignCollectionField 注釈。

上記のような新しいBookエンティティを作成してから、Libraryクラスに1対多の関係を追加しましょう。

@DatabaseTable(tableName = "libraries")
public class Library {  
    // ...
    
    @ForeignCollectionField(eager=false)
    private ForeignCollection<Book> books;
    
    // standard getters, setters
}

これに加えて、BookクラスにLibraryタイプのフィールドを追加する必要があります。

@DatabaseTable
public class Book {
    // ...
    @DatabaseField(foreign = true, foreignAutoRefresh = true) 
    private Library library;

    // standard getters, setters
}

ForeignCollectionには、タイプ Book:のレコードを操作するadd()メソッドとremove()メソッドがあります。

Library library = new Library();
library.setName("My Library");
libraryDao.create(library);

libraryDao.refresh(library);

library.getBooks().add(new Book("1984"));

ここでは、 library オブジェクトを作成し、新しいBookオブジェクトをbooksフィールドに追加しました。これにより、データベースにも保持されます。

コレクションは遅延ロード(eager = false)としてマークされているため、bookフィールドを使用する前にrefresh()メソッドを呼び出す必要があることに注意してください。

Bookクラスのlibraryフィールドを設定して関係を作成することもできます。

Book book = new Book("It");
book.setLibrary(library);
bookDao.create(book);

両方のBookオブジェクトがライブラリに追加されていることを確認するには、 queryForEq()メソッドを使用して、次のすべてのBookレコードを検索します。指定されたlibrary_id

assertEquals(2, bookDao.queryForEq("library_id", library).size());

ここで、 library_id は外部キー列のデフォルト名であり、主キーはlibraryオブジェクトから推測されます。

8. QueryBuilder

DAOを使用して、 QueryBuilder オブジェクトを取得し、それを利用してより強力なクエリを構築できます。

このクラスには、 selectColumns()、where()、groupBy()、 having()、countOf()、distinct()、 orderBy()、join()。

複数のBookが関連付けられているすべてのLibraryレコードを検索する方法の例を見てみましょう。

List<Library> libraries = libraryDao.queryBuilder()
  .where()
  .in("libraryId", bookDao.queryBuilder()
    .selectColumns("library_id")
    .groupBy("library_id")
    .having("count(*) > 1"))
  .query();

9. 結論

この記事では、ORMLiteを使用してエンティティを定義する方法と、オブジェクトとそれに関連するリレーショナルデータベースを操作するために使用できるライブラリの主な機能について説明しました。

この例の完全なソースコードは、GitHubにあります。