Expose custom query in Spring Boot Rest API with multiple joins - spring-boot

I have an Spring REST Api and a MySQL Database, now I would like to expose the result of an custom query with multiple joins.
I have tried multiple suggestions that I found online but none of them were working for me so far.
What I want to do is something like a read only DTO that has all the fields of my custom query so that in the end I have one api page exposing the DTO data as JSON so my client (Angular) can read the data from there.
I already tried to:
create an #RestController with an injected EntityManager that executes a NativeQuery and then populates the DTO with the returned data but since my DTO is no Entity I get an Hibernate Mapping Exception
create a custom Repository and its Impl but with a similar outcome
place the Query inside an existing #Entity that is part of the Query statement
What am I missing here? Do I have to annotate my DTO maybe? Cuttently it's just a POJO, I think the #Entity annotation is not the right thing here since I don't want a Table created from my DTO.

Fixed it by letting the Query return an Array of type Object and afterwards mapping it to the DTO Constructor.

Related

Is it necessary to use Entity annotation for Select query records from Database

I have spring boot application with JPA and MySQL. The table is already created and data are present. From the spring boot application, we need to create two API - get a particular record using id and get all the records. I created a model class but confused with usage of #Entity. Because I'm not going to insert/delete a record from the database. I want to use only for select the record.
For Select query (findBy), do we need to use #Entity annotation at the top of model class?
Yes, you would need to use #Entity to mark your model class, this tells JPA that your class is used for mapping to and from a database table. If you want to make sure that you don't accidentally overwrite the data, you could implement a check via #EntityListener, as described in this answer.

Spring data with MongoDB Views

To improve our query performances and hence the API response times, we created views on MongoDB by aggregating the data. However when we try to use the view using Spring Mongo template, running into several issues like View not supported.
Caused by: com.mongodb.MongoCommandException: Command failed with error 166 (CommandNotSupportedOnView): 'Namespace aiops.hostView is a view, not a collection' on server 192.168.20.166:30011. The full response is {​​​​​​​"ok": 0.0, "errmsg": "Namespace aiops.hostView is a view, not a collection", "code": 166, "codeName": "CommandNotSupportedOnView"}​​​​​​​
at com.mongodb.internal.connection.ProtocolHelper.getCommandFailureException(ProtocolHelper.java:175)
at com.mongodb.internal.connection.InternalStreamConnection.receiveCommandMessageResponse(InternalStreamConnection.java:303)
at com.mongodb.internal.connection.InternalStreamConnection.sendAndReceive(InternalStreamConnection.java:259)
Does Spring support MongoDB views out of the box? any example will greatly help!
Thank you in advance
This is somewhat old, but I will leave my solution in case someone stumbles on this, like I did.
As far as I know, you can't use the usual Spring Data approach: you can't annotate an Entity with the #Document(value="YOUR_VIEW_NAME") annotation and create a related repository extending the MongoRepository class.
But you can query the view directly from the MongoTemplate, passing along the name of your view.
Let's say you have a User entity defined like this:
public class User {
#Id
String id;
String name;
}
Then you can map it to the documents of a view named "userview", and query it like this:
Query query = new Query();
query.addCriteria(Criteria.where("name").is("Bob"));
// template is an object of class MongoTemplate that you can inject or autowire
List<User> users = template.find(query, User.class, "userview");
I recently faced the same problem, what #gere said is not entirely correct, you can use a view with spring data repositories but there are some limitations that are related to the limitation of the view itself.
In my case, the problem was that I was using annotation CompositeIndex and Indexed on the document which represents a view, and as MongoDB view uses the underlying collection indexes so it does not have the operation command to create an index for itself and when spring data tries to create an index on that view, MongoDB throws an exception. After removing those annotations, I was able to use them via my repository. I would suggest you use a read-only repository as well to prevent having a save method or delete as I think that is a view limitation too. if you search you can find examples of read-only repositories.
In your case, you need to find what operation you were trying to do on a normal collection that view does not support.

Spring Data JPA + Bytecode Enhancement

Is it possible to load #*ToOne attributes eagerly using JPA interface(Entity Graphs) which are set lazy using #LazyToOne , #LazyGroup in the parent entity class and enabled bytecode enhancement ? I am trying to load such attributes eagerly using entity graph but it is firing another query for such #*ToOne attributes when an parent entity is queried.
Trying to have another way to override static fetch type in entity classes including #LazyToOne which was added with bytecode enhancement.
Using Spring 5.1.3 , Spring JPA 2.2 , Hibernate 5.4.19
Update : Data JPA is working as expected and i could see joins for the attributes which i am trying to fetch eagerly but those lazy attributes are not being initialised with the join query response and hibernate causing each query on referencing attributes which were annotated with #LazyToOneOption.NO_PROXY and was already fetched eagerly using entity graph in my repository.
How can i avoid this second select which is not even required since i got the that data eagerly from entity graph in JPA respository ??
Any help would be highly appreciated.
Entity Graphs just like Hibernate fetch profiles apply regardless of what annotations you have on the association. If it does not, maybe there is a bug in Spring Data or maybe even Hibernate. It's probably best if you create a new JIRA issue with a test case reproducing the problem.
Having said that, I think this is the perfect use case for Blaze-Persistence Entity Views.
I created the library to allow easy mapping between JPA models and custom interface or abstract class defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure(domain model) the way you like and map attributes(getters) via JPQL expressions to the entity model.
An example DTO model could look like the following with Blaze-Persistence Entity-Views:
#EntityView(User.class)
public interface UserDto {
#IdMapping
Long getId();
String getName();
Set<RoleDto> getRoles();
#EntityView(Role.class)
interface RoleDto {
#IdMapping
Long getId();
String getName();
}
// Other mappings
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
UserDto a = entityViewManager.find(entityManager, UserDto.class, id);
The Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features

How to map a Spring Data JPA repository entity into a view model?

Here is the situation, I want to fetch an entity from database and map it to a new view domain model which has more or less properties, if this view model has more properties, signs the extra properties with default value. I want a map technique in JPA to complete this, which is similar to MyBatis mapping mechanism.
So how to do it?
Just load the entity, copy it over in the new entity, fill the unset properties with the desired default values and store it using JPA (possibly via Spring Data JPA).
For copying over the data from one entity to another you might want to look int Dozer or similar libraries.
You could also misuse Spring Data's projection support to query the original entity, but return it as the target entity with methods similar to the following:
interface SourceRepository<Source, Long> extends CrudRepository<Source, Long> {
List<Target> findTargetBy();
}
The resulting Target entities then could be stored again using another repository (you might have to set version and id properties to null to make it clear to the framework that these are new entities.

How do I execute named queries from a JPA EntityListener?

I have a requirement to set a date_updated value in my database for each row when that row is updated. Let's call the entity that I'm working with Order, which has a corresponding orders table in the database.
I've added the date_updated column to the orders table. So far, so good.
The #Entity Order object that I'm working with is provided by a third party. I do not have the ability to modify the source code to add a field called dateUpdated. I have no requirement to map this value to the object anyway - the value is going to be used for business intelligence purposes only and does not need to be represented in the Java entity object.
My problem is this: I want to update the date_updated column in the database to the current time each time an Order object (and its corresponding database table row) is modified.
Constraints:
We are using Oracle, Spring, JPA and Hibernate
I cannot use Oracle triggers to update the value. We are using a database replication technology that prevents us from using triggers.
My approach thus far has been to use a JPA EntityListener, defined in xml, similar to this:
<entity-mappings xmlns="....">
<entity class="com.theirs.OrderImpl">
<entity-listeners>
<entity-listener class="com.mine.listener.OrderJPAListener" />
</entity-listeners>
</entity>
</entity-mappings>
My listener class looks like this:
public class OrderJPAListener {
#PostPersist
#PostUpdate
public void recordDateUpdated(Order order) {
// do the update here
}
}
The problem I'm having is injecting any sort of persistence support (or anything at all, really) into my listener. Because JPA loads the listener via its methods, I do not have access to any Spring beans in my listener class.
How do I go about injecting an EntityManager (or any Spring bean) into my listener class so that I can execute a named query to update the date_updated field?
How do I go about injecting an EntityManager (or any Spring bean) into
my listener class so that I can execute a named query to update the
date_updated field?
As noted above JPA 2.1 supports injecting managed beans to an Entity Listener via CDI. Whether or not Spring supports this I am not sure. The folloiwng post proposes a Spring specific solution.
https://guylabs.ch/2014/02/22/autowiring-pring-beans-in-hibernate-jpa-entity-listeners/
A possible alternative approach would be however to override the SQL generated by Hibernate on an update which is possible as detailed below.
https://docs.jboss.org/hibernate/orm/3.6/reference/en-US/html/querysql.html#querysql-cud
This would be straightforward if you had the source as you would just need to add the #SQLUpdate annotation and tag on the additional date_update column. As you don't however you would need to look at redefining the metadata for that Entity via an xml configuration file and defining the sql-update statement as outlined above:
https://docs.jboss.org/hibernate/stable/annotations/reference/en/html/xml-overriding.html#xml-overriding-principles-entity
Since JPA 2.1 Entity Listeners are CDI managed. Have you tried using #PersistenceUnit annotation? Are you using JTA transaction type?
Otherwise you could use Persistence.createEntityManagerFactory within the Listener class to retrieve the Persistence Context.

Resources