Sử dụng ORM Ebean trong Play Framework

Cấu hình Ebean

Play đi kèm với ORM Ebean . Để enable tính năng này, hãy thêm plugin Play Ebean vào plugin SBT trong file project/plugins.sbt: addSbtPlugin("com.typesafe.sbt" % "sbt-play-ebean" % "4.0.1")

Và sau đó modify file build.sbt để enable plugin Play Ebean:

lazy val myProject = (project in file("."))
  .enablePlugins(PlayJava, PlayEbean)

Cấu hình Model

Play Ebean có hai components, một runtime library thực sự thao tác với database, và một plugin sbt giúp nâng cao biên dịch Java bytecode biên dịch của các Model để sử dụng với Ebean. Cả hai components này đều cần phải được cấu hình để Ebean biết được Model ở đâu.

Cấu hình runtime library

Runtime library có thể được cấu hình bằng cách đặt danh sách các packages và / hoặc các classes mà các Ebean models sống trong application configuration file. Ví dụ: nếu tất cả cácmodels nằm trong models package, hãy thêm các thông số sau vào conf/application.conf:

ebean.default = ["models.*"] Điều này định nghĩa một default Ebean server, sử dụng default data source, mà phải được cấu hình đúng. Bạn cũng có thể override tên của default Ebean server bằng cách định cấu hình ebeanconfig.datasource.default. Điều này có thể hữu ích nếu bạn muốn sử dụng databases riêng biệt để thử nghiệm và phát triển. Bạn thực sự có thể tạo rất nhiều Ebean servers bạn cần, và xác định rõ ràng các classes ánh xạ mapped với mỗi server:

ebean.orders = ["models.Order", "models.OrderItem"]
ebean.customers =  ["models.Customer", "models.Address"]

Trong ví dụ này, chúng ta có quyền truy cập vào haiEbean servers - mỗi cái sử dụng database riêng của mình.

Mỗi dòng cấu hình ebean. có thể map bất kỳ classes mà Ebean có thể quan tâm đến việc đăng ký (ví dụ. @Entity/Model classes, @Embeddables, custom ScalarTypes and CompoundTypes, BeanPersistControllers, BeanPersistListeners, BeanFinders, ServerConfigStartups, ...). Chúng có thể được liệt kê riêng biệt bằng dấu phẩy, and/or bạn có thể sử dụng ký tự đại diện .. Ví dụ, models. đăng ký với Ebean tất cả các classes trongmodels package mà Ebean có thể sử dụng.

Để tùy chỉnh cấu hình Ebean Server, bạn có thể thêm vào file conf/ebean.properties, hoặc tạo ra mộtinstance của ServerConfigStartup interface để thao tác Ebean ServerConfig trước khi server được khởi tạo.

Ví dụ, vấn đề khá phổ biến của việc giảm sequence batch size để giảm thiểu sequence gaps, có thể được giải quyết khá đơn giản với một class như thế này:

package models;

import io.ebean.config.ServerConfig;
import io.ebean.event.ServerConfigStartup;

public class MyServerConfigStartup implements ServerConfigStartup {
    public void onStart(ServerConfig serverConfig) {
        serverConfig.setDatabaseSequenceBatchSize(1);
    }
}

Lưu ý rằng Ebean cũng sẽ sử dụng một file conf/orm.xml (nếu có), để cấu hình <entity-mappings>.

Cấu hình sbt plugin

Theo mặc định, sbt plugin sẽ cố gắng tải file application.conf của bạn để khám phá cấu hình Model của bạn là gì. Nó sẽ làm việc trong một set up project đơn giản, tuy nhiên, trong một set up dự án đơn giản cho các dự án có nhiều sub project, trong đó file application.conf sống trong một dự án khác nhau nơi các Ebean Model tồn tại, điều này có thể không hoạt động. Trong trường hợp này bạn sẽ cần phải xác định bằng tay các Ebean Model cho mỗi sub project có chứa cácebean model, sử dụng cấu hình iteam playEbeanModels:

playEbeanModels in Compile := Seq("models.*") Ngoài việc định cấu hình các Model, bạn có thể muốn cấu hình enable debug. Điều này có thể được thực hiện bằng cách sử dụng playEbeanDebugLevel, với -1 là tắt, và 9 hiển thị số lượng lớn nhất của debug:

playEbeanDebugLevel := 4 Bạn cũng có thể cấu hình đối số tùy chỉnh cho ebean agent, điều này có thể được thực hiện bằng cách sử dụng playEbeanAgentArgs setting:

playEbeanAgentArgs += ("detect" -> "false") Cuối cùng, nếu bạn muốn tăng cường các Model trong phần tests của mình, bạn có thể thực hiện điều này bằng cách cấu hình ebean test configuration:

inConfig(Test)(PlayEbean.scopedSettings)
playEbeanModels in Test := Seq("models.*")

Sử dụng Model superclass Ebean định nghĩa một lớp cha thuận tiện cho các classes Ebean Model của bạn, io.ebean.Model. Đây là một Ebean class điển hình, được mapped trong Play:

package models;

import java.util.*;
import javax.persistence.*;

import io.ebean.*;
import play.data.format.*;
import play.data.validation.*;

@Entity
public class Task extends Model {

    @Id
    @Constraints.Min(10)
    public Long id;

    @Constraints.Required
    public String name;

    public boolean done;

    @Formats.DateTime(pattern="dd/MM/yyyy")
    public Date dueDate = new Date();

    public static final Finder<Long, Task> find = new Finder<>(Task.class);
}

Play đã được thiết kế để tự động tạo getter / setter để đảm bảo tính tương thích với các library mong đợi chúng sẵn có tại runtime (ORM, Databinder, JSON Binder, ...). Nếu Play phát hiện bất kỳ user-written getter/setter trong Model, nó sẽ không tạo trình getter / setter để tránh xung đột.

Như bạn thấy, chúng ta đã thêm một find static field, xác định một Finder cho một Entity kiểu Task với identifier là Long. Helper field giúp này sau đó được sử dụng để đơn giản hóa truy vấn Model:

// Find all tasks
List<Task> tasks = Task.find.all();

// Find a task by ID
Task anyTask = Task.find.byId(34L);

// Delete a task by ID
Task.find.ref(34L).delete();

// More complex task query
List<Task> cocoTasks = Task.find.query().where()
        .ilike("name", "%coco%")
        .orderBy("dueDate asc")
        .setFirstRow(0)
        .setMaxRows(25)
        .findPagedList()
        .getList();

Transactional actions

Theo mặc định Ebean sẽ sử dụng transactions. Tuy nhiên, các transactions này sẽ được tạo ra trước và commited hoặc rollbacked sau mỗi lần truy vấn, cập nhật, tạo hoặc xóa, như bạn thấy ở đây:

// Created implicit transaction
Task task = Task.find.byId(34L);
// Transaction committed or rolled back

task.done = true;

// Created implicit transaction
task.save();
// Transaction committed or rolled back

Vì vậy, nếu bạn muốn làm nhiều hơn một action trong cùng một transactions, bạn có thể sử dụng TxRunnableTxCallable:

import io.ebean.*;

...

Ebean.execute(() -> {
    // code running in "REQUIRED" transactional scope
    // ... as "REQUIRED" is the default TxType
    System.out.println(Ebean.currentTransaction());

    Task task = Task.find.byId(34L);
    task.done = true;

    task.save();
});

Nếu class của bạn là một action, bạn có thể chú thích action method với @play.db.ebean.Transactional để soạn action method với một Action mà nó sẽ tự động quản lý transaction:

import play.db.ebean.Transactional;

...

@Transactional
public Result done(long id) {
    Task task = Task.find.byId(34L);
    task.done = true;

    task.save();
    return ok();
}

Hoặc nếu bạn muốn có một cách tiếp cận truyền thống hơn bạn có thể begin, commit và các rollback transactions một cách rõ ràng:

Ebean.beginTransaction();
try {
    Task task = Task.find.byId(34L);
    task.done = true;

    task.save();

    Ebean.commitTransaction();
} finally {
    Ebean.endTransaction();
}

Reference

https://www.playframework.com/documentation/2.6.x/JavaEbean


All Rights Reserved