Mongodb Panache

MongoDB 是一个广为人知的 NoSQL 数据库,已被广泛使用。 但使用其原始API可能很麻烦,因为您需要将实体和查询表达为 MongoDB Document

MongoDB with Panache 提供了active record 风格 (和仓库) 让你方便使用 entity ,如您在 Hibernate ORM with Panache

它基于 MongoDB Client extension 创建。

This technology is considered preview.

In preview, backward compatibility and presence in the ecosystem is not guaranteed. Specific improvements might require to change configuration or APIs and plans to become stable are under way. Feedback is welcome on our mailing list or as issues in our GitHub issue tracker.

For a full list of possible extension statuses, check our FAQ entry.

先看一个示例

Panache 允许您像这样写MongoDB 实体:

public class Person extends PanacheMongoEntity {
    public String name;
    public LocalDate birth;
    public Status status;

    public static Person findByName(String name){
        return find("name", name).firstResult();
    }

    public static List<Person> findAlive(){
        return list("status", Status.Alive);
    }

    public static void deleteLoics(){
        delete("name", "Loïc");
    }
}

您有没注意到代码比使用 MongoDB API更紧凑和更易读? 这看起来很有意思吗? 看下去!

list() 方法开始可能令人吃惊。 它包含 PanacheQL 查询的片段 (JPQL的子集),并将其余部分放在上下文中。 这变得非常简洁,但可读性更好。 MongoDB 本地查询也被支持。
上面描述的基本上是 active record 模式, 有时也称实体模式。 MongoDB with Panache 也可以通过 PanacheMongoRepository 使用传统的 repository 模式.

成果

我们建议您按照下面章节指示,一步一步创建应用程序。 但是你也可以直接跳到已完成的例子。

克隆 Git 仓库: git clone https://github.com/quarkusio/quarkus-quickstarts.git, 或下载 压缩包

代码在 mongodb-panache-quickstart 目录 中。

创建 Maven 项目

首先,我们需要一个新项目。 通过以下命令创建一个新项目:

mvn io.quarkus:quarkus-maven-plugin:1.3.1.Final:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=mongodb-panache-quickstart \
    -DclassName="org.acme.mongodb.panache.PersonResource" \
    -Dpath="/persons" \
    -Dextensions="resteasy-jsonb,mongodb-panache"
cd mongodb-panache-quickstart

此命令生成一个 Maven 项目结构并导入 RESTEasy/JAX-RS, JSON-B and MongoDB with Panache extensions。 这样,quarkus-mongodb-panache 扩展已添加到你的 pom.xml

如果你不想生成一个新的项目,你可以在你的 pom.xml 中添加依赖:

<dependencies>
    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-mongodb-panache</artifactId>
    </dependency>
</dependencies>

配置 MongoDB with Panache

要开始:

  • application.properties 中添加您的设置

  • 让您的实体 extend PanacheMongoEntity (也可选用仓库模式)

  • 使用 @MongoEntity 注解指定数据库名称和collection名称 (它默认是实体名称)。

然后在 application.properties 中添加相关的配置属性。

# configure the MongoDB client for a replica set of two nodes
quarkus.mongodb.connection-string = mongodb://mongo1:27017,mongo2:27017
# mandatory if you don't specify the name of the database using @MongoEntity
quarkus.mongodb.database = person

MongoDB with Panache 使用 quarkus.mongodb.database 确定实体要存储的数据库名称。

对于MongoDB 客户端的高级配置,参阅 配置 MongoDB 数据库指南.

方案1:使用 active record 模式

定义您的实体

要定义Panache实体,只需 extend PanacheMongoEntity 并添加列为 public fields。 如果您需要自定义 collection 和/或数据库的名称, 您可以添加 @MongoEntity 注解到实体。

@MongoEntity(collection="ThePerson")
public class Person extends PanacheMongoEntity {
    public String name;

    // will be persisted as a 'birth' field in MongoDB
    @BsonProperty("birth")
    public LocalDate birthDate;

    public Status status;
}
注解 @MongoEntity 是可选的,它允许您配置 collection 名称和数据库名称。 这里的实体将存储在 ThePerson collection 中,而不是默认的 Person collection 。

MongoDB with Panache 使用 PojoCodecProvider 将您的实体映射到 MongoDB Document

您可以用以下注解来定制映射:

  • @BsonId:允许您自定义 ID 字段,见 Custom IDs

  • @BsonProperty: 自定义字段序列化的名称。

  • @BsonIgnore:在序列化过程中忽略某个字段。

If you need to write accessors, you can:

public class Person extends PanacheMongoEntity {
    public String name;
    public LocalDate birth;
    public Status status;

    // return name as uppercase in the model
    public String getName(){
        return name.toUpperCase();
    }

    // store all names in lowercase in the DB
    public void setName(String name){
        this.name = name.toLowerCase();
    }
}

And thanks to our field access rewrite, when your users read person.name they will actually call your getName() accessor, and similarly for field writes and the setter. This allows for proper encapsulation at runtime as all fields calls will be replaced by the corresponding getter/setter calls.

最常用的操作

一旦您写了实体,这里是您能够执行的最常见的操作:

// creating a person
Person person = new Person();
person.name = "Loïc";
person.birth = LocalDate.of(1910, Month.FEBRUARY, 1);
person.status = Status.Alive;

// persist it
person.persist();

person.status = Status.Dead;

// Your must call update() in order to send your entity modifications to MongoDB
person.update();

// delete it
person.delete();

// getting a list of all Person entities
List<Person> allPersons = Person.listAll();

// finding a specific person by ID
person = Person.findById(personId);

// finding a specific person by ID via an Optional
Optional<Person> optional = Person.findByIdOptional(personId);
person = optional.orElseThrow(() -> new NotFoundException());

// finding all living persons
List<Person> livingPersons = Person.list("status", Status.Alive);

// counting all persons
long countAll = Person.count();

// counting all living persons
long countAlive = Person.count("status", Status.Alive);

// delete all living persons
Person.delete("status", Status.Alive);

// delete all persons
Person.deleteAll();

所有的 list 方法都有相应的 stream 版本。

Stream<Person> persons = Person.streamAll();
List<String> namesButEmmanuels = persons
    .map(p -> p.name.toLowerCase() )
    .filter( n -> ! "emmanuel".equals(n) )
    .collect(Collectors.toList());
有个 persistorUpdate() 方法能保存或更新数据库中的一个实体,它使用 MongoDB 的 upsert 能力进行在单一查询中实现。

添加实体方法

在实体内部添加自定义查询。 这样,你和同事们就可以轻松地找到他们,查询与他们所操作的对象合用同一地点。 在您的实体类中添加它们作为静态方法是 Panache Active Recording 的方式。

public class Person extends PanacheMongoEntity {
    public String name;
    public LocalDate birth;
    public Status status;

    public static Person findByName(String name){
        return find("name", name).firstResult();
    }

    public static List<Person> findAlive(){
        return list("status", Status.Alive);
    }

    public static void deleteLoics(){
        delete("name", "Loïc");
    }
}

方案2:使用仓库模式

定义您的实体

您可以将实体定义为普通POJO。 如果您需要自定义 collection 和/或数据库的名称, 您可以添加 @MongoEntity 注解到实体。

@MongoEntity(collection="ThePerson")
public class Person  {
    public ObjectId id; // used by MongoDB for the _id field
    public String name;
    public LocalDate birth;
    public Status status;
}
注解 @MongoEntity 是可选的,它允许您配置 collection 名称和数据库名称。 这里的实体将存储在 ThePerson collection 中,而不是默认的 Person collection 。

MongoDB with Panache 使用 PojoCodecProvider 将您的实体映射到 MongoDB Document

您可以用以下注解来定制映射:

  • @BsonId:允许您自定义 ID 字段,见 Custom IDs

  • @BsonProperty: 自定义字段序列化的名称。

  • @BsonIgnore:在序列化过程中忽略某个字段。

您可以使用公共字段或私有字段的 getters/setters 。 如果您不想自己管理ID,您可以让您的实体扩展 PanacheMongoEntity.

定义您的仓库

当使用仓库时,让它们 implements PanacheMongoRepository 可以将活动记录模式完全相同的便利方法注入到你的仓库:

@ApplicationScoped
public class PersonRepository implements PanacheMongoRepository<Person> {

   // put your custom logic here as instance methods

   public Person findByName(String name){
       return find("name", name).firstResult();
   }

   public List<Person> findAlive(){
       return list("status", Status.Alive);
   }

   public void deleteLoics(){
       delete("name", "Loïc");
  }
}

PanacheMongoEntityBase 上定义的所有操作都可以在您的仓库类中使用,所以使用 与使用活动记录模式完全相同,但您需要注入:

@Inject
PersonRepository personRepository;

@GET
public long count(){
    return personRepository.count();
}

最常用的操作

一旦你写好仓库类,这里是你能够执行的最常见的操作:

// creating a person
Person person = new Person();
person.name = "Loïc";
person.birth = LocalDate.of(1910, Month.FEBRUARY, 1);
person.status = Status.Alive;

// persist it
personRepository.persist(person);

person.status = Status.Dead;

// Your must call update() in order to send your entity modifications to MongoDB
personRepository.update(person);

// delete it
personRepository.delete(person);

// getting a list of all Person entities
List<Person> allPersons = personRepository.listAll();

// finding a specific person by ID
person = personRepository.findById(personId);

// finding a specific person by ID via an Optional
Optional<Person> optional = personRepository.findByIdOptional(personId);
person = optional.orElseThrow(() -> new NotFoundException());

// finding all living persons
List<Person> livingPersons = personRepository.list("status", Status.Alive);

// counting all persons
long countAll = personRepository.count();

// counting all living persons
long countAlive = personRepository.count("status", Status.Alive);

// delete all living persons
personRepository.delete("status", Status.Alive);

// delete all persons
personRepository.deleteAll();

所有的 list 方法都有相应的 stream 版本。

Stream<Person> persons = personRepository.streamAll();
List<String> namesButEmmanuels = persons
    .map(p -> p.name.toLowerCase() )
    .filter( n -> ! "emmanuel".equals(n) )
    .collect(Collectors.toList());
有个 persistorUpdate() 方法能保存或更新数据库中的一个实体,它使用 MongoDB 的 upsert 能力进行在单一查询中实现。
其余文件只显示活动记录模式的用法。 但要记住,它们也可以用仓库模式进行。 仓库模式示例已省略。

高级查询

分页

如果你的 collection 包含足够小的数据集,你只需使用 liststream 方法。 对于更大的数据 您可以使用等效的 find 方法返回一个 PanacheQuery ,您可以用它分页:

// create a query for all living persons
PanacheQuery<Person> livingPersons = Person.find("status", Status.Alive);

// make it use pages of 25 entries at a time
livingPersons.page(Page.ofSize(25));

// get the first page
List<Person> firstPage = livingPersons.list();

// get the second page
List<Person> secondPage = livingPersons.nextPage().list();

// get page 7
List<Person> page7 = livingPersons.page(Page.of(7, 25)).list();

// get the number of pages
int numberOfPages = livingPersons.pageCount();

// get the total number of entities returned by this query without paging
int count = livingPersons.count();

// and you can chain methods of course
return Person.find("status", Status.Alive)
    .page(Page.ofSize(25))
    .nextPage()
    .stream()

PanacheQuery 类型有许多其他方法来处理分页和返回流。

排序

所有接受查询字符串的方法也接受可选的 Sort 参数,它允许您抽象排序:

List<Person> persons = Person.list(Sort.by("name").and("birth"));

// and with more restrictions
List<Person> persons = Person.list("status", Sort.by("name").and("birth"), Status.Alive);

Sort 类有很多方法可以添加列和指定排序方向。

简化查询

通常,MongoDB 查询是这个形式: {'firstname': 'John', 'lastname':'Doe'} ,这我们称之为 MongoDB 原生查询。

如果你想可以使用它们,但我们也支持称之为 PanacheQL ,它可以被看作是 JPQL (或 HQL) 的子集并允许您轻松表示查询。 MongoDB with Panache 会将其映射到 MongoDB 原生查询。

如果您的查询不是以 { 开头的,我们将认为它是 PanacheQL 查询:

  • <singlePropertyName> (and single parameter) 将展开为 {'singleColumnName': '?'}

  • <query> 将展开为 {<query>} 我们会将PanacheQL 查询映射到 MongoDB 原生查询形式。 我们将这些操作符映射到 MongoDB:'and', 'or' ( 混用 'and' 和 'or' 当前不支持), '=', '>', '>=', '<', '⇐', '!=', 'is null', 'is not null', 操作符 'like' 映射到 MongoDB $regex .

以下是一些查询示例:

  • firstname = ?1 and status = ?2 将映射到 {'firstname': ?1, 'status': ?2}

  • amount > ?1 and firstname != ?2 将映射到 {'amount': {'$gt': ?1}, 'firstname': {'$ne': ?2}}

  • lastname like ?1 将映射到 {'lastname': {'$regex': ?1}}. 请注意这是 MongoDB regex 而不是SQL 中的 like 。

  • lastname is not null 将映射为 {'lastname':{'$exists': true}}

我们还处理一些基本的日期类型转换:所有类型为 DateLocalDateLocalDateTimeInstant 的字段都将映射到BSON 日期 使用 ISODate 类型(UTC日期时间)。 MongoDB POJO 编解码器不支持 ZonedDateTimeOffsetDateTime ,因此您应该先将它们转换。

MongoDB with Panache 也支持通过提供 Document 查询来扩展的 MongoDB 查询,find/list/stream/count/delete 方法都支持。

查询参数

您可以通过索引(从1开始) 将查询参数传递给本机和 PanacheQL 查询,如下所示:

Person.find("name = ?1 and status = ?2", "Loïc", Status.Alive);
Person.find("{'name': ?1, 'status': ?2}", "Loïc", Status.Alive);

或者使用 Map 带名称:

Map<String, Object> params = new HashMap<>();
params.put("name", "Loïc");
params.put("status", Status.Alive);
Person.find("name = :name and status = :status", params);
Person.find("{'name': :name, 'status', :status}", params);

或者使用方便类 Parameters 或者生成一个 Map

// generate a Map
Person.find("name = :name and status = :status",
         Parameters.with("name", "Loïc").and("status", Status.Alive).map());

// use it as-is
Person.find("{'name': :name, 'status': :status}",
         Parameters.with("name", "Loïc").and("status", Status.Alive));

每个查询操作通过索引(Object…​),或通过名称 (Map<String,Object> or Parameters) 接受传递参数。

当您使用查询参数时, 请注意 PanacheQL 查询将引用对象参数名,但原生查询将引用 MongoDB 字段名。

想象一下以下实体:

public class Person extends PanacheMongoEntity {
    @BsonProperty("lastname")
    public String name;
    public LocalDate birth;
    public Status status;

    public static Person findByNameWithPanacheQLQuery(String name){
        return find("name", name).firstResult();
    }

    public static Person findByNameWithNativeQuery(String name){
        return find("{'lastname': ?1}", name).firstResult();
    }
}

findByNameWipanacheQLQuery()findByNameWindNativeQuery() 方法都会返回相同的结果,但在 PanacheQL 中写入的查询将使用实体字段名称:name, 原生查询将使用 MongoDB 字段名称: lastname

查询投影

查询投影可以使用 PanacheQuery 对象上的 project(Class) 方法完成,而这个方法是 find() 方法返回的。

您可以用它限制数据库返回哪些字段, ID 字段将永远返回,但它不必包含在投影类中。

为此,您需要创建一个只包含投影字段的 POJO。 此 POJO 需要使用 @ProjectionFor(Entity.class) 来注解,其中 Entity 是您实体类的名称。 投影类的字段名称或 getters 将用于限制从数据库加载字段。

PanacheQL 和原生查询都可以投影。

import io.quarkus.mongodb.panache.ProjectionFor;
import org.bson.codecs.pojo.annotations.BsonProperty;

// using public fields
@ProjectionFor(Person.class)
public class PersonName {
    public String name;
}

// using getters
@ProjectionFor(Person.class)
public class PersonNameWithGetter {
    private String name;

    public String getName(){
        return name;
    }

    public void setName(String name){
        this.name = name;
    }
}

// only 'name' will be loaded from the database
PanacheQuery<PersonName> shortQuery = Person.find("status ", Status.Alive).project(PersonName.class);
PanacheQuery<PersonName> query = Person.find("'status': ?1", Status.Alive).project(PersonNameWithGetter.class);
PanacheQuery<PersonName> nativeQuery = Person.find("{'status': 'ALIVE'}", Status.Alive).project(PersonName.class);
不需要使用 @BsonProperty 来定义自定义列映射,因为实体类别的映射将被使用。
你可以将你的投影类 extends 另一个类。 这时,父类也需要使用 @ProjectionFor 注解。

事务

自4.0版以来,MongoDB提供ACID 事务。 MongoDB with Panache 不支持他们。

自定义 ID

ID 常常是一个令人触摸的问题。 在 MongoDB 中,它们通常是数据库自动生成 ObjectId 类型。 在 MongoDB with Panache 中,ID 是由 org.bson.types.ObjectId 类型 的 id 字段定义, 但我们想你可能需要自定义它们。

您可以通过扩展 PanacheMongoEntityBase 而不是 PanacheMongoEntity 来指定 ID策略。 然后 你通过注解 @BsonId 来声明想要的 public 字段:

@MongoEntity
public class Person extends PanacheMongoEntityBase {

    @BsonId
    public Integer myId;

    //...
}

如果您正在使用仓库模式,那么您将想要扩展 PanacheMongoRepositoryBase 而不是 PanacheMongoRepository 并指定您的 ID 类型作为额外类型的参数:

@ApplicationScoped
public class PersonRepository implements PanacheMongoRepositoryBase<Person,Integer> {
    //...
}

当使用 ObjectId 时,MongoDB 将自动为您提供一个值。 但如果您使用自定义字段类型, 您需要自己提供值。

如果你想要在REST 接口中公开 ObjectId,它 的值可能很难使用。 所以我们创建了JSON-B 和 Jackson providers,将它们序列化/反序列化为 String ,如果你的项目依赖RESTEasy JSON-B extension 或 RESTEasy Jackson extension 会自动注册它们。

使用 Kotlin 数据类

Kotlin data classes are a very convenient way of defining data carrier classes, making them a great match to define an entity class.

But this type of class comes with some limitations: all fields needs to be initialized at construction time or be marked as nullable, and the generated constructor needs to have as parameters all the fields of the data class.

MongoDB with Panache uses the PojoCodec, a MongoDB codec which mandates the presence of a parameterless constructor.

Therefore, if you want to use a data class as an entity class, you need a way to make Kotlin generate an empty constructor. To do so, you need to provide default values for all the fields of your classes. The following sentence from the Kotlin documentation explains it:

On the JVM, if the generated class needs to have a parameterless constructor, default values for all properties have to be specified (see Constructors).

If for whatever reason, the aforementioned solution is deemed unacceptable, there are alternatives.

First, you can create a BSON Codec which will be automatically registered by Quarkus and will be used instead of the PojoCodec. See this part of the documentation: Using BSON codec.

Another option is to use the @BsonCreator annotation to tell the PojoCodec to use the Kotlin data class default constructor, in this case all constructor parameters have to be annotated with @BsonProperty: see Supporting pojos without no args constructor.

This will only work when the entity extends PanacheMongoEntityBase and not PanacheMongoEntity, as the ID field also needs to be included in the constructor.

An example of a Person class defined as a Kotlin data class would look like:

data class Person @BsonCreator constructor (
    @BsonId var id: ObjectId,
    @BsonProperty("name") var name: String,
    @BsonProperty("birth") var birth: LocalDate,
    @BsonProperty("status") var status: Status
): PanacheMongoEntityBase()

Here we use var but note that val can also be used.

The @BsonId annotation is used instead of @BsonProperty("_id") for brevity’s sake, but use of either is valid.

The last option is to the use the no-arg compiler plugin. This plugin is configured with a list of annotations, and the end result is the generation of no-args constructor for each class annotated with them.

For MongoDB with Panache, you could use the @MongoEntity annotation on your data class for this:

@MongoEntity
data class Person (
    var name: String,
    var birth: LocalDate,
    var status: Status
): PanacheMongoEntity()

]] == Reactive Entities and Repositories

MongoDB with Panache 可以对实体及仓库使用反应式实现。 为此,您需要在定义实体时使用反应式变体:ReactivePanacheMongoEntityReactivePanacheMongoEntityBase, 当定义仓库时: ReactivePanacheMongoRepository or ReactivePanacheMongoRepositoryBase.

Mutiny

MongoDB with Panache 的反应式API使用 Mutiny 反应式类型,如果你不熟悉的话,先看下 反应式入门

Person 类的反应式变体将是:

public class ReactivePerson extends ReactivePanacheMongoEntity {
    public String name;
    public LocalDate birth;
    public Status status;

    // return name as uppercase in the model
    public String getName(){
        return name.toUpperCase();
    }

    // store all names in lowercase in the DB
    public void setName(String name){
        this.name = name.toLowerCase();
    }
}

You will have access to the same functionalities of the imperative variant inside the reactive one: bson annotations, custom ID, PanacheQL, …​ 但是您的实体或仓库的方法都会返回反应式类型。

看下示例中等效方法的反应式变体:

// creating a person
ReactivePerson person = new ReactivePerson();
person.name = "Loïc";
person.birth = LocalDate.of(1910, Month.FEBRUARY, 1);
person.status = Status.Alive;

// persist it
Uni<Void> cs1 = person.persist();

person.status = Status.Dead;

// Your must call update() in order to send your entity modifications to MongoDB
Uni<Void> cs2 = person.update();

// delete it
Uni<Void> cs3 = person.delete();

// getting a list of all persons
Uni<List<ReactivePerson>> allPersons = ReactivePerson.listAll();

// finding a specific person by ID
Uni<ReactivePerson> personById = ReactivePerson.findById(personId);

// finding a specific person by ID via an Optional
Uni<Optional<ReactivePerson>> optional = ReactivePerson.findByIdOptional(personId);
personById = optional.map(o -> o.orElseThrow(() -> new NotFoundException()));

// finding all living persons
Uni<List<ReactivePerson>> livingPersons = ReactivePerson.list("status", Status.Alive);

// counting all persons
Uni<Long> countAll = ReactivePerson.count();

// counting all living persons
Uni<Long> countAlive = ReactivePerson.count("status", Status.Alive);

// delete all living persons
Uni<Long>  deleteCount = ReactivePerson.delete("status", Status.Alive);

// delete all persons
deleteCount = ReactivePerson.deleteAll();
如果您引入 quarkus-resteasy-mutiny extension 结合 RESTEasy 来使用 MongoDB with Panache, 你就可以在 JAX-RS 接口中直接返回反应式类型。

The same query facility exists for the reactive types, but the stream() methods act differently: they return a Multi (which implement a reactive stream Publisher) instead of a Stream.

它允许更高级的反应式使用方式,例如,您可以通过 RESTEasy 来发送服务器发送事件(SSE):

import org.jboss.resteasy.annotations.SseElementType;
import org.reactivestreams.Publisher;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

@GET
@Path("/stream")
@Produces(MediaType.SERVER_SENT_EVENTS)
@SseElementType(MediaType.APPLICATION_JSON)
public Multi<ReactivePerson> streamPersons() {
    return ReactivePerson.streamAll();
}
@SseElementType(MediaType.APPLICATION_JSON) 让 RESTEasy 将对象序列化成 JSON.

如何和为什么我们简化 MongoDB API

在写MongoDB实体时, 有很多烦人的东西用户需要勉强处理,例如:

  • Duplicating ID logic: most entities need an ID, most people don’t care how it’s set, because it’s not really relevant to your model.

  • 无聊的 getters and setters: 既然Java 不支持语言属性,我们必须创建字段 然后生成这些字段的getters和设置器,即使他们实际上不会做比读/写 字段更多的事情。

  • 传统的 EE 模式建议将实体定义(模型) 从您可以做的操作中拆分 (DAOs, 存储库), 但这实际上需要在状态和操作之间进行非自然的分割,即使 我们永远不会对对象结构中的普通对象做任何类似的事情, 状态和方法属于同一类。 此外,这样每个实体需要两个类,and requires injection of the DAO or Repository where you need to do entity operations, which breaks your edit flow and requires you to get out of the code you’re writing to set up an injection point before coming back to use it.

  • MongoDB 查询是超强的,但常用操作过于琐碎,requiring you to write queries even when you don’t need all the parts.

  • MongoDB 查询是基于 JSON 的 所以你将需要一些字符串操纵或使用 Document 类型,它将需要大量的样板代码。

用 Panache,采取了一种办法来处理所有这些问题:

  • 让您的实体 extend PanacheMongoEntity: 它有一个自动生成的 ID 字段。 如果您需要 个自定义ID策略,您可以 extend PanacheMongoEntityBase 自己处理ID。

  • 使用公共字段。 摆脱无聊的 getter 和 setters。 Under the hood, we will generate all getters and setters that are missing, and rewrite every access to these fields to use the accessor methods. This way you can still write useful accessors when you need them, which will be used even though your entity users still use field accesses.

  • 使用 active record 模式:将您所有的实体逻辑放在您的实体类静态方法中,无需创建 DAO。 您的实体父类有许多非常有用的静态方法,您可以在实体类中添加自己的内容。 用户只需输入 Person. 并在一个地方完成所有操作就可以开始使用你的实体 Person

  • 无需写下您不需要的查询的部分:写入 Person.find("order by name")Person.find("name = ?1 and status = ?2", "Loïc", Status.Alive) 甚至 Person.find("name", "Loïc").

总的来说:使用 Panache 后 MongoDB 看起来如此精简。

在外部项目或jars中定义实体

MongoDB with Panache 依赖于编译时字节码增强您的实体。 如果在构建 Quarkus 应用程序的同一个项目中定义实体一切都可以正常工作。 如果实体来自外部项目或 jars, 你可以通过通过Jandex 索引来确保你的 jar 被视为一个 Quarkus 应用程序库, 请参阅 CDI指南中 如何生成Jandex 索引 。 这将使 Quarkus 能够索引和增强您的实体,好像它们在当前项目中一样。

quarkus.pro 是基于 quarkus.io 的非官方中文翻译站 ,最后更新 2020/04 。
沪ICP备19006215号-8
QQ交流群:1055930959
微信群: