I have an Entity "Parent" which has a relationship with 4 Set of > "Children".
On Neo4jRepository save method ids of some of the related children return null. To be more precise it has different behavior on every call to save method e.g times it saved three of the lists correctly but return null for the ids of one set of children.
api response in postman
Related
I have an application that exposed an endpoint to insert multiple records into the DB. It takes in a list of ids and inserts them into the DB.
Now I have already worked on an endpoint, where I was getting a DTO and then I inserted that DTO into the DB which gave back the UID of the record. Using this UID I created the URI that I used to create and return the ResponseEntity.created() like below:
return ResponseEntity.created(URI.create(location)).body(roId);
The challenge here is that it works for only one location and one UID. Is it possible to do that same in case I am inserting multiple records in the DB and I will be getting a list of ids? Is this even the right approach?
NOTE: I do not want to return the List<ResponseEntity<Long>>. I require ResponseEntity<List<Long>>.
I'm developing a RESTful webservice with spring-data as its data access layer, backed by JPA/Hibernate.
It is very common to have relationships between domain entities. For example, imagine an entity Product which has a Category entity.
Now, when the client POSTs a Product representation to a JAX-RS method. That method is annotated with #Transactional to wrap every repository operation in a transaction. Of course, the client only sends the id of an already existing Category, not the whole representation, just a reference (the foreign key).
In that method, if I do this:
entity = repository.save(entity);
the variable entity now has a Category with only the id field set. This didn't surprise me. I wasn't expecting a save (SQL insert) to retrieve information on related objects. But I need the whole Product object and related entities to be able to return to the user.
Then I did this:
entity = repository.save(entity);
entity = repository.findOne(entity.getId());
that is, retrieve the object after persisting it, within the same transaction/session.
To my surprise, the variable entity didn't change anything. Actually, the database didn't even get a single select query.
This is related with Hibernate's cache. For some reason, when in the same transaction, a find does not retrieve the whole object graph if that object was previously persisted.
With Hibernate, the solution appears to be to use session.refresh(entity) (see this and this). Makes sense.
But how can I achieve this with spring data?
I would like to avoid to create repetitive custom repositories. I think that this functionality should be a part of spring data itslef (Some people already reported this in spring data's forum: thread1, thread2).
tl;dr
References between entities in the web layer need to be made explicit by using links and should not be hidden behind semi-populated object instances. References in the persistence layer are represented by object references. So there should be a dedicated step transforming one (the link) into the other (the fully populated object reference).
Details
It's an anti-pattern to hand around backend ids as such and assume the marshaling binding doing the right thing. So the clients should rather work with links and hand those to the server to indicate they want to establish a connection between an already existing resource and one about to be created.
So assuming you have the existing Category exposed via /categories/4711, you could post to your server:
POST /products
{ links : [ { rel : "category", href : "/categories/4711" } ],
// further product data
}
The server would the instantiate a new Product instance, populate it with additional data and eventually populate the associations as follows:
Identify properties to be populated by looking up the link relation types (e.g. the category property here.
Extract the backend identifier from the given URI
Use the according repository to lookup the related entity instance
Set it on the root entity
So in your example boiling down to:
Product product = new Product();
// populate primitive properties
product.setCategory(categoryRepository.findOne(4711));
productRepository.save(product);
Simply posting something like this to the server:
POST /products
{ category : {
id : 1, … },
…
}
is suboptimal for a lot of reasons:
You want the persistence provider to implicitly persist a Product instance and at the same time 'recognize' that the Category instance referred to (actually consisting of an id only) is not meant to be persisted but updated with the data of the already existing Category? That's quite a bit of magic I'd argue.
You essentially impose the data structure you use to POST to the server to the persistence layer by expecting it to transparently deal with the way you decided to do POSTs. That's not a responsibility of the persistence layer but the web layer. The whole purpose of a web layer is to mitigate between the characteristics of an HTTP based protocol using representations and links to a backend service.
To the question "Save Differences with Entity ID" I found the following answer:
"For Entities, Id property cannot be null, so you need to map this class as ValueObject. If so,
Id property is treated as regular property and it not goes to GlobalId of this object."
My question is:
Why can't an entity be treated as NEW if the Id is NULL?
I have an object graph that is fetched from the database, and between two javers commits an entity is added to a list in the graph.
Two commits and in the second commit there is a new entity (Id NULL)
Get the change => exeption because Javers can't create a GlobalId.
I can get arround this by doing EntityManager - persist (creates Id:s), but I would like to avoid doing that. The present code may do a persist later or it just lets the transaction finish.
Because the Id is NULL, the entity is NEW. Would it be possible to generate a unigue temp Id (allow Id = NULL) to be able to create the GlobalId?
In the change list, the entity would be reported as NEW. No need to compare with earlier commits.
You should compare/commit your objects when they are fully initialized so when they have Ids.
An entity without Id can't be handled by JaVers for several reasons:
it can't be compared to other entity/version (diff algorithm is based on GlobalIds)
it can't be queried from JaVersRepository (queries use GlobalIds)
If you are using Hibernate, compare/commit your new objects after Hibernate assigns them Ids from sequences.
Another options:
don't use sequence-generated values as JaVers Id but some business identifiers
if an Entity doesn't have a business identifier you can generate UUID in a constructor and use it as JaVers id (and also database PK if you like)
I want to save data of a form into two tables simultaneously. The form contains multiple identical rows with some fields like
item, unit, unit_price, total.
1.) In the table1 I would like to save some data like id(auto generated, primary key), date, creator.
2.) In table2 I would like to save the id(auto generated, primary key), fid(id of the table1, foreign key), item, unit, unit price, total. Remember, in table2 multiple rows will be save from the form data.
I can't figure it out. Please help me with a valid step by step example, and please don't use static or pre-defined data, take the data from form only.
Is your form an HTML form on a web page, and are you writing a Spring MVC application? Have you setup Spring Security, or some other authentication mechanism such that you know who the user is? If so, here is one approach:
Define a plain old Java object (POJO) with fields id, unit, unit-price, total, creator, currentDate; perhaps you would name it Item.
Define another plain old Java object perhaps named "ItemHistory", with its own ID and a reference to an Item.
In the first POJO ("Item") include a reference to a list of ItemHistorys.
Annotate both classes with Hibernate/JPA annotations, such that the Item has a OneToMany relationship to ItemHistory.
Define a Spring MVC controller with a method annotated as a POST method, with an Item as one parameter, and an Authentication as another parameter (supposing you have configured Spring Security, the Authentication will automatically be populated with the identity of the currently-logged-in user. In this method, set the currentDate and author of the Item to the current date and the principal from the Authentication parameter. If it is a new Item (no id yet), add the first ItemHistory as a copy of the Item itself. If it is an existing item, add another ItemHistory if needed.
Define a Spring bean, perhaps named ItemService, with a method annotated as transactional, that takes an Item and saves it. Call this bean from the REST controller. Such a Spring bean is known as a DAO (data access object).
There are other strategies, but if you already have Spring MVC, Spring Security, and Hibernate/JPA configured to your needs, this one is pretty straight-forward.
I have a Spring 4 and Hibernate 5 back-end RESTful web-service. This works great and is all unit tested. The front-end is a SmartGWT 5.0p application which uses DataSources, not RestDataSources to communicate with the back-end.
The front-end SmartGWT 5.0p uses a listgrid to edit data, and then the ListGrid is attched to a datasource. Only the edited data in the ListGrid is sent back, not the entire row. If I could, I'd like to be able send backthe entire listgrid row with edited data, and the unedited data. If I could get an answer to that, that would be great.
Or, the alternate is we let SmartGWT only send back part of the data which is edited. This comes to the back-end as JSON and is changed into an Object/Entity. The controller/end-point is not in a session yet, but then we call a method in the service layer which is transactional.
So, then question becomes we have a detached object in a session in the method in the service layer. We have a detached object with a database primary key ... but it also has 1 or 2 fields of updated data, and now we want to merge that data back to the database. We can't call an update with this entity because with the partial data, some of the fields are being set to null. In reality, we want to pull back the item from the databae, update the edited fields, and then write the data back to the database.
I could do this all manually ... but do I have to? I expect there is a more graceful way to handle this.
Thanks!
This is only a partial answer:
I can make SmartGWT combine old values and new values with a link I found here:
SMARTGWT DataSource (GWT-RPC-DATASource) LISTGRID
And the code is as follows:
private ListGridRecord getEditedRecord(DSRequest request)
{
// Retrieving values before edit
JavaScriptObject oldValues = request
.getAttributeAsJavaScriptObject("oldValues");
// Creating new record for combining old values with changes
ListGridRecord newRecord = new ListGridRecord();
// Copying properties from old record
JSOHelper.apply(oldValues, newRecord.getJsObj());
// Retrieving changed values
JavaScriptObject data = request.getData();
// Apply changes
JSOHelper.apply(data, newRecord.getJsObj());
return newRecord;
}
This JSON string contains the new fields updated, and the old fields. When this json string is sent back to the RESTful back end, the Jackson Mapper creates an entity and puts all the fields in, this is essentially a detached entity. It's an object outside of the session, but the id resides in the database.
Because I have a complete entity, I can all an update, and that works.
Problem solved.
BUT, I'd still like to find out an elegant solution for taking a detached entity, get the original record from the database, and then merge these two objects, and then finally update the record.
In the Service layer in Spring which has a transaction, and creates the session,
a manual process, which I don't want to do might look something like this:
1) get the id from the updatedEntity
2) get that attachedEntity from the database using that id
3) compare the fields
if( updatedEntity.updateField1 != null )
{ attachedEntity.setField1(updatedEntity.updateField1) }
If I had to do step 3 for multiple fields,
that's not very elegant.
4) Update attachedEntity to the database, because it now has updated fields.
So, again, an elegant solution to fix this might be helpful. Thanks!