Introduction to ORMLite – ORMLite简介

最后修改: 2017年 10月 10日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

ORMLite is a lightweight ORM library for Java applications. It provides standard features of an ORM tool for the most common use cases, without the added complexity and overhead of other ORM frameworks.

ORMLite是一个用于 Java 应用程序的轻量级 ORM 库。它为最常见的使用情况提供了ORM工具的标准功能,而没有增加其他ORM框架的复杂性和开销。

It’s main features are:

它的主要特点是。

  • defining entity classes by using Java annotations
  • extensible DAO classes
  • a QueryBuilder class for creating complex queries
  • generated classes for creating and dropping database tables
  • support for transactions
  • support for entity relationships

In the next sections, we’ll take a look at how we can set up the library, define entity classes and perform operations on the database using the library.

在接下来的章节中,我们将看看如何设置库,定义实体类并使用库对数据库进行操作。

2. Maven Dependencies

2.Maven的依赖性

To start using ORMLite, we need to add the ormlite-jdbc dependency to our pom.xml:

为了开始使用ORMLite,我们需要将ormite-jdbc依赖性添加到我们的pom.xml

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

By default, this also brings in the h2 dependency. In our examples, we’ll use an H2 in-memory database, so we don’t need another JDBC driver.

默认情况下,这也带来了h2的依赖性。在我们的例子中,我们将使用一个H2内存数据库,所以我们不需要另一个JDBC驱动程序。

If you want to use a different database, you’ll also need the corresponding dependency.

如果你想使用一个不同的数据库,你也需要相应的依赖关系。

3. Defining Entity Classes

3.定义实体类

To set up our model classes for persistence with ORMLite, there are two primary annotations we can use:

为了用ORMLite设置我们的模型类的持久性,有两个主要的注解我们可以使用。

  • @DatabaseTable for the entity class
  • @DatabaseField for the properties

Let’s start by defining a Library entity with a name field and a libraryId field which is also a primary key:

让我们首先定义一个Library实体,它有一个name字段和一个libraryId字段,也是一个主键。

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

    @DatabaseField(canBeNull = false)
    private String name;

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

The @DatabaseTable annotation has an optional tableName attribute that specifies the name of the table if we don’t want to rely on a default class name.

@DatabaseTable注解有一个可选的tableName属性,如果我们不想依赖默认的类名,可以指定表的名称。

For every field that we want to persist as a column in the database table, we have to add the @DatabaseField annotation.

对于每一个我们希望作为数据库表中的一个列而持久化的字段,我们必须添加 @DatabaseField 注解。

The property that will serve as a primary key for the table can be marked with either id, generatedId or generatedSequence attributes. In our example, we choose the generatedId=true attribute so that the primary key will be automatically incremented.

作为表的主键的属性可以用idgeneratedIdgeneratedSequence属性标记。在我们的例子中,我们选择generatedId=true属性,这样主键就会自动递增。

Also, note that the class needs to have a no-argument constructor with at least package-scope visibility.

另外,请注意,该类需要有一个无参数的构造函数,至少要有包-范围可见性。

A few other familiar attributes we can use for configuring the fields are columnName, dataType, defaultValue, canBeNull, unique.

我们可以使用其他几个熟悉的属性来配置字段,包括columnName, dataType, defaultValue, canBeNull, unique

3.1. Using JPA Annotations

3.1.使用JPA注解

In addition to the ORMLite-specific annotations, we can also use JPA-style annotations to define our entities.

除了ORMLite特有的注解外,我们还可以使用JPA风格的注解来定义我们的实体

The equivalent of the Library entity we defined before using JPA standard annotations would be:

我们之前使用JPA标准注解定义的Library实体的等价物将是。

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

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

Although ORMLite recognizes these annotations, we still need to add the javax.persistence-api dependency to use them.

尽管ORMLite能够识别这些注解,但我们仍然需要添加javax.persistence-api依赖来使用它们。

The full list of supported JPA annotations is @Entity, @Id, @Column, @GeneratedValue, @OneToOne, @ManyToOne, @JoinColumn, @Version.

支持的JPA注解的完整列表是 @Entity, @Id, @Column, @GeneratedValue, @OneToOne, @ManyToOne, @JoinColumn, @Version

4. ConnectionSource

4.ConnectionSource

To work with the objects defined, we need to set up a ConnectionSource.

为了处理定义的对象,我们需要设置一个ConnectionSource

For this, we can use the JdbcConnectionSource class which creates a single connection, or the JdbcPooledConnectionSource which represents a simple pooled connection source:

为此,我们可以使用创建单个连接的JdbcConnectionSource类,或者代表简单池化连接源的JdbcPooledConnectionSource

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

// work with the connectionSource

connectionSource.close();

Other external data source with better performance can also be used, by wrapping them in a DataSourceConnectionSource object.

也可以使用其他性能更好的外部数据源,方法是将它们包装在一个DataSourceConnectionSource对象中。

5. TableUtils Class

5.TableUtils

Based on the ConnectionSource, we can use static methods from the TableUtils class to perform operations on the database schema:

基于ConnectionSource我们可以使用TableUtils类的静态方法来对数据库模式进行操作

  • createTable() – to create a table based on a entity class definition or a DatabaseTableConfig object
  • createTableIfNotExists() – similar to the previous method, except it will only create the table if it doesn’t exist; this only works on databases that support it
  • dropTable() – to delete a table
  • clearTable() – to delete the data from a table

Let’s see how we can use TableUtils to create the table for our Library class:

让我们看看如何使用TableUtils来为我们的Library类创建表。

TableUtils.createTableIfNotExists(connectionSource, Library.class);

6. DAO Objects

6.DAO 对象

ORMLite contains a DaoManager class that can create DAO objects for us with CRUD functionality:

ORMLite包含一个DaoManager类,可以为我们创建具有CRUD功能的DAO对象

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

The DaoManager doesn’t regenerate the class for each subsequent call of createDao(), but instead reuses it for better performance.

DaoManager不会在随后每次调用createDao()时重新生成该类,而是重用它以获得更好的性能。

Next, we can perform CRUD operations on Library objects:

接下来,我们可以对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);

The DAO is also an iterator that can loop through all the records:

DAO也是一个迭代器,可以循环浏览所有记录。

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

However, ORMLite will only close the underlying SQL statement if the loop goes all the way to the end. An exception or a return statement may cause a resource leak in your code.

然而,ORMLite只有在循环一直进行到结束时才会关闭基础SQL语句。异常或返回语句可能会导致你的代码中出现资源泄漏。

For that reason, the ORMLite documentation recommends we use the iterator directly:

由于这个原因,ORMLite文档建议我们直接使用迭代器。

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

This way, we can close the iterator using a try-with-resources or a finally block and avoid any resource leak.

这样,我们可以使用try-with-resourcesfinally 块来关闭迭代器,避免任何资源泄漏。

6.1. Custom DAO Class

6.1.自定义DAO类

If we want to extend the behavior of the DAO objects provided, we can create a new interface which extends the Dao type:

如果我们想扩展所提供的DAO对象的行为,我们可以创建一个新的接口,扩展Dao类型。

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

Then, let’s add a class that implements this interface and extends the BaseDaoImpl class:

然后,让我们添加一个实现这个接口的类,并扩展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);
    }
}

Note that we need to have a constructor of this form.

注意,我们需要有一个这种形式的构造函数

Finally, to use our custom DAO, we need to add the class name to the Library class definition:

最后,为了使用我们的自定义DAO,,我们需要在Library类定义中添加类名。

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

This enables us to use the DaoManager to create an instance of our custom class:

这使我们能够使用DaoManager来创建我们自定义类的实例。

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

Then we can use all the methods from the standard DAO class, as well as our custom method:

然后我们可以使用标准DAO类中的所有方法,以及我们的自定义方法。

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

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

7. Defining Entity Relationships

7.定义实体关系

ORMLite uses the concept of “foreign” objects or collections to define relationships between entities for persistence.

ORMLite使用 “外来 “对象或集合的概念来定义实体之间的关系,以便持久化。

Let’s take a look at how we can define each type of field.

让我们来看看我们如何定义每种类型的字段。

7.1. Foreign Object Fields

7.1.外来对象字段

We can create a unidirectional one-to-one relationship between two entity classes by using the foreign=true attribute on a field annotated with @DatabaseField. The field must be of a type that’s also persisted in the database.

我们可以通过在一个用@DatabaseField注释的字段上使用foreign=true属性,在两个实体类之间创建一个单向的一对一关系。这个字段必须是在数据库中也被持久化的类型。

First, let’s define a new entity class called Address:

首先,让我们定义一个名为Address的新实体类。

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

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

Next, we can add a field of type Address to our Library class which is marked as foreign:

接下来,我们可以在我们的Library类中添加一个Address类型的字段,它被标记为foreign

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

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

    // standard getters, setters
}

Notice that we’ve also added two more attributes to the @DatabaseField annotation: foreignAutoCreate and foreignAutoRefresh, both set to true.

请注意,我们还向@DatabaseField注解添加了两个属性。foreignAutoCreateforeignAutoRefresh,都设置为true。

The foreignAutoCreate=true attribute means that when we save a Library object with an address field, the foreign object will also be saved, provided its id is not null and has a generatedId=true attribute.

foreignAutoCreate=true属性意味着当我们保存一个带有address字段的Library对象时,外国对象也将被保存,只要它的id不是空的并且有generatedId=true属性。

If we set foreignAutoCreate to false, which is the default value, then we’d need to persist the foreign object explicitly before saving the Library object that references it.

如果我们将foreignAutoCreate设置为false,也就是默认值,那么我们就需要在保存引用它的Library对象之前明确地持久化这个外来对象。

Similarly, the foreignAutoRefresh=true attribute specifies that when retrieving a Library object, the associated foreign object will also be retrieved. Otherwise, we’d need to refresh it manually.

同样,foreignAutoRefresh=true属性指定在检索Library对象时,相关的外来对象也将被检索。否则,我们就需要手动刷新它。

Let’s add a new Library object with an Address field and call the libraryDao to persist both:

让我们添加一个新的Library对象,它有一个Address字段,并调用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);

Then, we can call the addressDao to verify that the Address has also been saved:

然后,我们可以调用addressDao来验证Address也已被保存。

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

7.2. Foreign Collections

7.2.国外的收款情况

For the many side of a relationship, we can use the types ForeignCollection<T> or Collection<T> with a @ForeignCollectionField annotation.

对于关系的many方,我们可以使用ForeignCollection<T>Collection<T>类型,并加上@ForeignCollectionField注解。

Let’s create a new Book entity like the ones above, then add a one-to-many relationship in the Library class:

让我们创建一个新的Book实体,就像上面那些实体一样,然后在Library类中添加一个一对多的关系。

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

In addition to this, it’s required that we add a field of type Library in the Book class:

除此之外,还要求我们在Book类中添加一个Library类型的字段。

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

    // standard getters, setters
}

The ForeignCollection has add() and remove() methods that operate on the records of type Book:

ForeignCollectionadd()remove()方法,对Book类型的记录进行操作:

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

libraryDao.refresh(library);

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

Here, we’ve created a library object, then added a new Book object to the books field, which also persists it to the database.

在这里,我们创建了一个library对象,然后在books字段中添加了一个新的Book对象,这也将其持久化到数据库中。

Note that since our collection is marked as lazily loaded (eager=false), we need to call the refresh() method before being able to use the book field.

注意,由于我们的集合被标记为懒惰加载(eager=false),我们需要调用refresh()方法然后才能使用book字段。

We can also create the relationship by setting the library field in the Book class:

我们也可以通过在Book类中设置library字段来创建这种关系。

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

To verify that both Book objects are added to the library we can use the queryForEq() method to find all the Book records with the given library_id:

为了验证这两个对象是否被添加到图书馆,我们可以使用queryForEq()方法来找到所有具有给定图书馆_id记录。

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

Here, the library_id is the default name of the foreign key column, and the primary key is inferred from the library object.

这里,library_id是外键列的默认名称,而主键是从library对象推断出来的。

8. QueryBuilder

8.QueryBuilder

Each DAO can be used to obtain a QueryBuilder object that we can then leverage for building more powerful queries.

每个DAO都可以用来获得一个QueryBuilder对象,然后我们可以利用它来构建更强大的查询。

This class contains methods that correspond to common operations used in an SQL query such as: selectColumns(), where(), groupBy(), having(), countOf(), distinct(), orderBy(), join().

该类包含对应于SQL查询中常用操作的方法,例如。selectColumns(), where(), groupBy(), having(), countOf(), distinct(), orderBy(), join() 。

Let’s see an example of how we can find all the Library records that have more than one Book associated:

让我们看一个例子,说明我们如何找到所有有一个以上关联的图书馆记录。

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

9. Conclusion

9.结论

In this article, we’ve seen how we can define entities using ORMLite, as well as the main features of the library that we can use to manipulate objects and their associated relational databases.

在这篇文章中,我们已经看到了如何使用ORMLite定义实体,以及该库的主要功能,我们可以用它来操作对象和它们相关的关系数据库。

The full source code of the example can be found over on GitHub.

该示例的完整源代码可以在GitHub上找到over