简体   繁体   中英

Quarkus and how to implement in-memory, entities and DAO

I'm currently migrating my database layer (entity and DAO) from JavaEE to Quarkus (or well, from wls to OpenShift) and can't quite get my head around some details:

At the moment I have the current structure:

  • Information class RegisteredTime.java
  • Entity class defining column names and such, RegisteredTimeEntity.java, with matching persistence.xml
  • MapStruct mapper class to map between RegisteredTime.java and RegisteredTimeEntity.java
  • DAO-class to make db-access easier, RegisteredTimeDAO.java
  • structure.ddl to define DB-structure
  • In-memory class TestDB.java which extends JdbcDaoSupport (springframework) and uses Derby

My test class RegisteredTimeDAOTest which uses TestDB for in-memory:

class RegisteredTimeDAOTest extends Specification {

private RegisteredTimeId registeredTimeId;
private RegisteredTimeData registeredTimeData;

private long userId;
private int userVersion;
private RegisteredTime registeredTime;
private Long userNumber;
private LocalDate startDate, endDate
private Boolean registration
private Boolean registrationApproved
private String registration
private String timeType
private LocalDate incomingDate

@Shared
private EntityManager entityManager
@Shared
private EntityManagerFactory entityManagerFactory
@Shared
private TestDB db
static SingleConnectionDataSource dataSource
private RedovisadTidEntity registeredTimeEntity
private RegisteredTimeDAO instance
private Gson gson

def setupSpec() {
    db = new TestDB("test")
    db.start()
    dataSource = new SingleConnectionDataSource(db.getJDBCUrl(), true)

    entityManagerFactory = Persistence.createEntityManagerFactory("EKN-Persistence-Test")
    entityManager = entityManagerFactory.createEntityManager()
}

def cleanupSpec() {
    if (entityManager != null) {
        entityManager.close()
    }
    if (entityManagerFactory != null) {
        entityManagerFactory.close()
    }
    db.shutdown()
}

def setup() {
    userId = 1
    userVersion = 1
    userNumber = 1991010101011L
    startDate = LocalDate.of(2020, 01, 01)
    endDate = LocalDate.of(2020, 01, 31)
    registration = false
    registrationApproved = false
    registration = null
    timeType = TimeType.STANDARD_TIME;
    incomingDate = LocalDate.of(2020, 02, 03)

    registeredTimeId = new RegisteredTimeId(userId, userVersion)
    registeredTimeData = RegisteredTimeData.newRegisteredTimeDataBuilder()
            .userNumber(userNumber)
            .startDate(startDate)
            .endDate(endDate)
            .registration(registration)
            .registrationApproved(registrationApproved)
            .timeType(timeType)
            .incomingDate(incomingDate)
            .build()

    registeredTime = new RegisteredTime().newRedovisadTidBuilder()
            .registeredTimeId(registeredTimeId)
            .registeredTimeData(registeredTimeData)
            .build()

    registeredTimeEntity = RegisteredTimeMapper.INSTANCE.toRegisteredTimeEntity(registeredTime)
    instance = new RegisteredTimeDAO(entityManager)
}

def cleanup() {
    instance = null
}

def "Save RegisteredTime"() {
    given:
    Statement statement = dataSource.getConnection().createStatement()
    statement.executeQuery("SELECT * FROM registeredtime")
    ResultSet rs = statement.getResultSet()
    gson = new Gson()

    when:
    entityManager.getTransaction().begin()
    instance.save(registeredTime)
    entityManager.getTransaction().commit()

    then:
    while (rs.next()) {
        assert rs.getInt(2) == userVersion
        assert rs.getLong(3) == userNumber
        assert gson.fromJson(rs.getString(4), RegisteredTimeData.class).equals(registeredTimeData)
        assert rs.getTime(5) != null
    }
}

def "Get RegisteredTime"() {
    when:
    entityManager.getTransaction().begin()
    RegisteredTime registeredTimeGet = instance.get(1000, userVersion)
    entityManager.getTransaction().commit()

    then:
    assert registeredTimeGet.getRegisteredTimeId().getAnsokanId() == userId
    assert registeredTimeGet.getRegisteredTimeId().getAnsokanVersion() == userVersion
    assert registeredTimeGet.getRegisteredTimeData().getKundId() == userNumber
    assert registeredTimeGet.getRegisteredTimeData().getFromdatum() == startDate
    assert registeredTimeGet.getRegisteredTimeData().getTomdatum() == endDate
    assert registeredTimeGet.getRegisteredTimeData().getAnmalanAF() == registration
    assert registeredTimeGet.getRegisteredTimeData().getFranvarogodkandAF() == registrationApproved
    assert registeredTimeGet.getRegisteredTimeData().getTimeType() == timeType
    assert registeredTimeGet.getRegisteredTimeData().getAngavsviddatum() == incomingDate
}

}

I've been lurking around at quarkus.io and read the following:

https://quarkus.io/guides/datasource

https://quarkus.io/guides/hibernate-orm (probably the most important one)

https://quarkus.io/guides/getting-started (ofc)

https://quarkus.io/guides/gradle-tooling (using gradle)

  • An entity class is still required, but EntityManagerFactory is being taken care off and Datasource and EntityManger can just be injected, right?

  • Will I have to rewrite my TestDB or is there an "out of the box" solution? I looked at Zero Config Setup (DevServices), but this doesn't allow me to configure the db. I don't want to extend springframework anymore.

  • Do I need a DAO if I use Hibernate WITHOUT Panache?

I assume you're using Spock for your tests.

Quarkus only support JUnit5, so you should try with Spock 2.0-M5 that is based on JUnit5 and if possible use the Quarkus JUnit5 support via its quarkus-junit5 extension.

There is an issue for Quarkus and Spock support , you can watch it.

Note that there is no support for Groovy nor Spock from Quarkus.

As an alternative, you can also try this Quarkus Spock extension , no idea what's its state is, I only found it via a Google search.

Regarding your questions:

An entity class is still required, but EntityManagerFactory is being taken care off and Datasource and EntityManger can just be injected, right?

If you are using the Quarkus Hibernate ORM extension, it's a regular Hibernate integration, so a JPA implementation, so you need to define JPA entity classes. Then you can inject an EntityManager . You can also inject a Datasource but it's better to use the EntityManager as it provides higher level integrations.

Will I have to rewrite my TestDB or is there an "out of the box" solution? I looked at Zero Config Setup (DevServices), but this doesn't allow me to configure the db. I don't want to extend springframework anymore.

If you can use @QuarkusTest support, it will start your application so you can use a memory database like H2 or Derby. There is a test support to automatically starts an H2database via a Quarkus test ressource, see the Starting services before the Quarkus application starts section of the Quarkus test guide that explains how to launch an H2 database thanks to io.quarkus.test.h2.H2DatabaseTestResource .

Devservices is also a good way to do it, it will run a real database inside a docker container, so if you didn't configure any datasource but use one of the Quarkus JDBC extensions (like quarkus-jdbc-postgresql for example), it will run a docker container in both dev and test for this database.

Two more things can help you achieve what you want: Quarkus has support for flyway or liquibase to manage database migration, and you can have specific test properties via the %test configuration profile (for exemple to run dedicated sql import file on test).

Do I need a DAO if I use Hibernate WITHOUT Panache?

Well, if you need a DAO I suggest using Hibernate with Panache that is a nice extension that allows to easily implements a DAO on top of your entity. But it depends on how you want to design your application. It's up to you to use a DAO or not, and to use Hibernate with Panache for your DAO or not.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM