Mostrando entradas con la etiqueta spring data. Mostrar todas las entradas
Mostrando entradas con la etiqueta spring data. Mostrar todas las entradas

miércoles, 22 de noviembre de 2017

Spring Data Rest: Many to Many relations with extra atrributes





In many articles can see that if we want work many to many relations with extra colmuns the post/put requests must is done from  Classroom or ClassType entities in several steps. Example:

curl -i -X POST -H "Content-Type:application/json"
  -d "{\"name\":\"Room 1\"}" http://localhost:8080/Classrooms

curl -i -X POST -H "Content-Type:application/json"
  -d "{\"name\":\"Aerobic\"}" http://localhost:8080/ClassTypes

curl -i -X PUT -H "Content-Type:text/uri-list"
  --data-binary @uris.txt http://localhost:8080/Classrooms/1/ClassTypes

The uris.txt file contains the URIs of the ClassTypes, each on a separate line:
http://localhost:8080/ClassTypes/1

The problem is when i need do this in one transaction. To do this I need change focus and use as repository the Classroom/ClassType entity. In this case i could do this curl request:

curl -i -X POST -H "Content-Type:application/json" -d '{"id":{"classroom":"1","classType":"1"}, "classMax": 80}' http://localhost:8762/classroomproxy/classroomClassTypes/1_1

The JPA entity definition:

Classroom/ClassType



The repository


As the relation Classroom/ClassType (N to M) doesn't allow null, both for Classroom and for ClassType must load the information before saving in the database. If that is not done hibernate will generate an error saying "null reference". With Spring Data Rest we can handle the  creation events. Before creating we can get the class information of entities relations and then set ClassroomClassType


Id Converter

To allow the customization of how entity ids are exposed in URIs generated.


Configuration






viernes, 4 de agosto de 2017

Overriding Spring Data REST Response Handlers to share news methods in all repositories

With my obsession for reusing all developments. I decided include all features from my module Spring Data Extension into Spring Data Rest Extension.  Hence, I can use all my extensions of spring data across rest in any proyect, without having to create mapping request in each one of the projects. In this line, I avoid repeat code and avoid have to do unit test by each repository that i make.

To explain how i have extended the spring data rest, i use like sample, the updating embedded documents that i made in spring data extension.

The more important is creates my own rest repository controller.

This class must have marked @RepositoryRestController annotation.



As we can see in the figure above, the mapping url is the union between BASE_MAPPING and "{id}/mergeembedded/{embeddedProperty}".


  • BASE_MAPPING: Contain the base path and repository name.
  • {id}: Identifier of the repository. In this point isn't used, but we'll see that the id is handled by PersistentEntityResourceHandlerMethodArgumentResolver.
  • {embeddedProperty}: Property name of the domain to get embedded information.


Another important thing in this class is get a invoker to execute, (in this case), the merge function. We get the invoker object using resourceInformation.getInvoker(). RootResourceInformation is the class that serves as bridge between repository rest controller and repository.

The next step is connect our repository invoker with RootResourceInformation. This connection is done by the class that resolves the arguments of the request.



The spring guys have provided us a method called postProcess where we can do this.

Spring Data Rest when processes the patch method does a merge between request content, (repository domain), and the persistent repository . This domain is sended to controller and is recoveried across getContext(). In my case, this operation don't want do it, because the merge embedded function already does this operation. I wan't get the original request domain in my custom controller. To change this behaviour, we have override PersistentEntityResourceHandlerMethodArgumentResolver.



Depending of a request header property and patch method is applied the update no merge feature or the default function.

The next step consists in says to spring data rest configuration that it uses the new funcionality. Hence, we override RepositoryRestMvcConfiguration. This class configure all necesary for spring data rest.



Finally, we going to create a configuration interface to do more easy the configuration to the developer.



How can we use this news features in our project?. We going to see a sample.

Steps:


  1. Define domains. Look at MongoDomain and MongoEmbeddedDomain.
  2. Define repository. Look at MongoRepository.
  3. Define @EnabledRepositoryExtensionRestMvc. Look at RestWebMvcConfiguration

Once defined all necesary in my project, we can use the news rest services methods across the curl utility or whatever. Look sample at integration test.


Full Sorce code.


miércoles, 18 de mayo de 2016

Custom behavior for embedded documents using Spring Data Mongo repositories

One of the most common tasks when working with entity-relation models is create relations between tables N to M. This involves creating three tables in the relational model. Sometimes, this behavior is also necessary to apply it for non-relational models like mongodb. In this case, we could have a main document which it contains an embedded document with (N to M) relational information. An example could be, when we want save the orders references into users document, all in the same document of users, using mongo embedded documents.

Of course, do something like this is very easy with Spring Data MongoDB. The problem is when we want to add or update items in the embedded document. Imagine the following scenario, a user make an order and adds the order reference to the users document, and before saving, his brother with the same account, adds another order reference to the basket, (the order reference is saved into user document with the same key of user). When some of them save the user document with order references, one of these two references will be lost. The problem is that when we save the document with Spring Data Mongo is saved according what we have previously read, so it could have concurrency problems.


To solve this problem, I thing that we should perform the operations to add or update items of a embedded document, using addToSet and set mongo operators. In this way,  we can add or update items partially to the embedded documents, without affecting others items, because we work directly with database and not with the memory.


¿How does it work?


We configure repositoryFactoryBeanClass for spring data repository can use the new feature.



We create the document that we will embed into the main document. Carful !!, the embedded document must have an identifier for each item, we must mark the identifier property with the attribute @Id



We create the main document that contain the embedded document. In our case, the embedded document is TestMongoEmbedeedEntity type.

 
We create the repository class that reference to TestMongoEntity document.



 
We are ready to perform the operations to add and update items in embedded document.

Steps:

1) We wire repository.

 

2) We call mergeEmbeddedRelation method of the repository that will insert or update in the collection for each embedded item. The function know whether can insert or update depending of if the item exists or don't exist in mongodb collection.

 

Parameters of mergeEmbeddedRelation:

testMongoEntity: Main document. Main document contains the embedded items that will be insert or update.

"embeddedEntities" : Define the property to get the embedded document items. 

 


To see all code click here.