H
H
HaruAtari2015-04-04 23:38:35
Java
HaruAtari, 2015-04-04 23:38:35

How is the connection of models with the database in java / scala applications?

Good afternoon.
It so happened that in almost all applications in the development of which I participated, the interaction in the database was implemented through ActiveRecords. For web projects, this is normal. All the main models contained the logic of work and at the same time were a reflection of the tables from the database.
Now I'm trying to join the world of Java / Scala development. I understand that a different approach is being practiced here. There are models - simple classes containing logic, and there are ORM classes that represent tables from the database. I don't understand how to tie it together.
I messed around with Scala syntax (I was superficially familiar with Java). Decided to make a simple blog. Unfurled the application on PlayFramework2 (standard typesafe template). Everything is clear with controllers, configs, views. But with models plugging.
Added slick. But I can't find a proper tutorial anywhere. I reviewed kure rap on github, 3 different approaches are used everywhere. The examples on their website describe only how to work with the query builder (in its various manifestations). But I can't figure out how to connect normal model classes to the database.
Please, tell me where can I find a description of the main approaches to working with the database through models? Both java and scala will do. I need to understand the essence. Or can you show a repository with a simple application, but in which you can see how the work with the database works from start to finish?
Sorry for the rambling question. I'm just in shock. Everything is new, a lot of things are not clear.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
B
bromzh, 2015-04-07
@HaruAtari

In the Java world, there are many ways to organize communication with a database and communication of models with a database in particular. There is a standard - JPA. In the spring world, there is a JPA compatibility layer, and there are other solutions. In Scala, you can use both the above solutions and your own (here it already depends on the framework used).
I will describe how it works in JPA.
First, you describe the connection of the entire application with the database in the persistence.xml file. In it, you describe persistence-units - persistence units, the connection of models with the database. Roughly speaking, you can use both local resources (RESOURCE_LOCAL - communication occurs not through the application server, but through third-party efforts, the connection is described in the xml file) and JTA resources (the connection is configured on the server, in the application you get the desired DataSource by name).
Then you create entity classes. You create a regular (POJO) class with the annotation Entity , describe the fields, getters and setters. With annotations, you can set up all sorts of things: the name of the table in the database, the name of the field, set relationships, type of receipt (LAZY / EAGER), cascading, auto-generation of primary keys, etc.
Then you need to create a class that will provide an interface for working with entities. Usually, for each entity, you need to make your own class. There are several implementations and names of these classes. NetBeans, for example, creates facade classes : one abstract and one abstract-derived facade per entity. The link is clear, I think. Each facade is a bean ( Stateless annotation ). EntityManager is injected into it:

@PersistenceContext(unitName = "AffableBeanPU")
private EntityManager em;

With a configured connection to the database (in persistence.xml), em will have the necessary implementation of this manager, through which all the magic happens. The advantage is that all requests automatically use transactions.
Well, then, in the code, you just need to inject this facade through the EJB annotation and use it (for example, to implement the REST API):
import org.foo.example.entities.Foo;
import org.foo.example.facades.FooFacade;

@Path("foo")
@Consumes({"application/json", "application/xml"})
@Produces({"application/json", "application/xml"})
class FooResource {

    @EJB
    FooFacade facade;

    @GET
    public List<Foo> getAll() {
        return facade.findAll();
    }

    @POST
    public Foo create(Foo item) {
        facade.create(item);
        return item;
    }

    @GET
    @Path("{id}")
    public Foo getOne(@PathParam("id") Integer id) {
        return facade.find(id);
    }

    @PUT
    @Path("{id}")
    public Foo update(@PathParam("id") Integer id, Foo item) {
        item.setId(id);
        facade.update(item);
        return item;
    }

    @DELETE
    @Path("{id}")
    public void delete(@PathParam("id") Integer id) {
        facade.remove(facade.find(id));
    }    
}

I downloaded a demo application , you can take a look.
The bottom line is this: we put wildfly, add a user. We start the server. You can go to the admin panel 127.0.0.1:9990
There, on the Configuration-> Datasources tab, there will be 1 data source - ExampleDS. This h2 is a built-in database, which in this case is spinning in the RAM and is reset when the server is restarted. We set up resources in the persistence.xml
file : we specify the name persistence-unit, and its type is JTA. Thus, there is no need to configure anything locally, the application receives everything through a resource that is configured on the server itself, by its name (java:jboss/datasources/ExampleDS). The only thing we specify in the config
<property name="hibernate.hbm2ddl.auto" value="update" />
so that tables in the database are automatically created (if they do not exist). There are 2 entities in the entities
package : User and Post . Both are annotated with Entity , so JPA can work with them. There are also annotations for entity validation in entities (these are all sorts of NotNull , Size , Min , Valid , etc.). Also, there is a simple two-way communication. The Post entity has a ManyToOne relationship to the User entity, the User entity has a OneToMany relationshipwith a list of user posts. The last link is needed to provide cascading at the JPA level, but there are no getters / setters for it, because I do not want this list to get out when the user is received. In a good way, you need to remove it, and in the post table (which is associated with the Post entity ), you yourself need to register the cascading when deleting, because the user should not particularly know what is in his dependents.
Next, the dao package contains classes for accessing entities.
AbstractDao is an abstract generic class that describes operations for managing entity storage. All methods there are trivial, except for getting.
In general, there are several ways to get an entity. You can use simple SQL queries, you can specify named queries ( NamedQuery ), which can be described either through an annotation of the same name or in code. The latter have the bonus of type safety.
And one more option is dynamic queries through CriteriaBuilder . JPA generates metaclasses for classes annotated with the Entity annotation . Queries can be built, including using these metaclasses. The big plus is that such queries can (and should) be made type-safe ( CriteriaQuery , TypedQuery ). And the IDE does not swear by type casting, which would be in the case of simple untyped requests. Generally, according toThis link has a detailed description of such type-safe queries.
Special attention to the findWithLazy and findAllWithLazy methods . In the Post entity , the owner field is marked as a ManyToOne relationship with a lazy fetch type ( fetch = FetchType.LAZY ). It’s hard to get such a field just like that: lazy loading only works within the session: a session was created, data was requested, the session was closed. And lazy fields are not added to the returned object by default. There are several ways to overcome this. You can remove laziness ( fetch = FetchType.EAGER ). You can call the size() methodfor the collection field. You can manually get the fields. I have done exactly that. The findWithLazy and findAllWithLazy methods are passed a list of fields required to retrieve. I create a request to get the root element: Root<T> root = criteriaQuery.from(entityClass);, and then in a loop I get the required fields: for (String field : fields) { root.fetch(field); }. When the query is executed, these fields will be attached to the result.
In the UserDao and PostDao classes, I specify the Stateless annotation for CDI and implement the getEntityManager() abstract method to get the PersistenceManager instance . I implement the instance itself through the PersistenceContext annotation , where as the unitName parameterI specify the name persistence-unit, which I designated in persistence.xml .
And finally, the use of DAO classes in the application ( resources package ). I am building a simple REST API using JAX-RS. For each entity, I create my own resource, into which I implement the required DAO class through the EJB annotation . There, I think, everything is obvious.
The description of the repository indicates how to run and test the whole thing.
I hope everything is clear.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question