Spring data JPA save() return less/incorrect child and parent association mapping fields [duplicate] - spring-boot

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.

Related

Why is my spring boot app creating another record in the database instead of merging them together?

AHere's the setup:
Springboot, springboot-data-jpa, hibernate.
I have one entity, a Review, that has a property that has a many-to-one relationship with another entity, a vehicle. The vehicle entity conversely has a one-to-many relationship with the review entity.
To create the review entity via a POST endpoint, I give the vehicle entity as of the properties in the JSON.
This works fine, not only is the review record added in the database but it goes ahead and creates the vehicle entity as well. The only issue is that in the case where the vehicle already exists, instead of making that connection, it creates another record with the exact same information so I have a duplicate vehicle entity.
Is this because I should be handling the creation of the vehicle entity on my own instead of relying on hibernate? Am I just missing some annotation I'm not aware of?
Originally I was getting an error about flushing or something so I added the Cascade.ALL annotation to the review class 'vehicle' property and that fixed that problem. I tried changing the Cascade type as it seems to be relevant somehow but it either breaks the server or doesn't work at all.

is this a good idea to implement validation in entity framework POCO entities in dabtase first?

It`s seems that the best place to implement validation is as close as possible to the database, so when I use entity framework the nearest objects are the entities, in my case the POCO entities.
The reason for that is that if I want to reuse this POCO entities, the validation is implemented in the POCO objects and then there are less posibilities to insert worng data in the database.
this also avoid that someone try to insert incorrect data in the databse creating another application, or because he does not implement the validation. So it is more secure.
One way to do that is using partial classes that extends the POCO entities and that implements the IValidatableObject interface and return a list of validationresult.
But other way is the following. I have a common assembly that has the following:
One interface that declare the methods that need to implement the repositories.
The POCO entities that will be used by the repositories.
One class with utilities, such as copy entities and methods to validate the data of the entities.
Then I can create many repositories that use different versions of EF or another technology and all of them use the common assembly. This repositories implements the validation using the methods in the common library.
In this case I implement the validation only once. The only problem is that the repositories need to call the methods to validate the data.
But there are advantages in this way, from my point of view. For example, I can validate the data of the entities depending on the type of the operation. For example, if I am adding a new record and the primary key as an autonumeric, if the ID is not 0, then I can throw an exception, or if I try to delete a register when the ID is 0, then I don't need to send the command to the database.
So this second solution solves the problem to implement the validation as close as possible to the database, bacause is used in the repository, that is the element that access to the database, but has the problem that if some developer creates a new repository and not use the validation methods, I can have incorrect data in the database.
So my question is if the best option is to use validation with partial classes or to use a common library and the validation is implemented in the repositories, that is really what the users will use.
Thanks.
OK - phew, big question. My opinion is that the APPLICATION DOMAIN of the application is the boss of everything. The database is just an add-on service. So, the application domain should ultimately validate ALL objects that are being SENT somewhere. No need to validate object coming out of the DB because they were validated going in.
As an example, what if you were creating some object that needed to be sent off to a web service and it needed validation. Lets say it was never going near the database or the repositories. Once the DOMAIN business objects have been validated, they can then be sent for persistence or anywhere else.
Another thing to consider is what you mean by validation. Does it mean the datatypes are correct? Does it mean the business object is valid? Does it mean the business object is valid in the given context? It could mean all or only some of these things.
As an example, what if your system allows users to partially update records (common with very long input forms). The business object may only become valid when ALL the required data is captured, but the database allows persistence of "partial" data. In other words, you can save the business object to the database although it is not valid for further processing yet. etc etc....

WebAPI - odata service adding ForeignKey

i am building my the model using ODataModelBuilder, i am trying to create navigation property however in the metadata i dont see any foreginkey indication, in my solution i am not using EF, so there is no foreignKey attribute, is it possible to add it by code?
As you clarified in your comment, the reason you want to add foreign key information is because your client application is not including related entities when you query the main entity. I don't think foreign keys are the problem here.
As an example, I'll use two entity types: Customer and Order. Every Customer has some number of associated Orders, so I have a navigation property on Customer called Orders that points to a collection of Orders. If I issue a GET request to /MyService.svc/Customers(1), the server will respond with all of the Customer's information as well as URLs that point to the related Order entities*. I won't, by default, get the data of each related Order within the same payload.
If you want a request to Customers(1) to include all of the data of its associated Orders, you would add the $expand query option to the request URI: /MyService.svc/Customers(1)?$expand=Orders. Using the WCF Data Services client (DataServiceContext), you can do this with .Expand():
DataServiceQuery<Customer> query = context.Customers.Expand("Orders");
However, WebAPI OData doesn't currently support $expand (the latest nightly builds do though, so this will change soon).
The other approach would be to make a separate request to fill in the missing Order data. You can use the LoadProperty() method to do this:
context.LoadProperty(customer, "Orders");
The LoadProperty approach should work with WebAPI as it stands today.
I know this doesn't answer your original question, but I hope addresses your intent.
*In JSON, which is the default format for WebAPI OData services, no links will show up on the wire, but they are still there "in spirit". The client is expected to be able to compute them on its own, which the WCF Data Services Client does.

Core Data cross storage fetched property

I'm currently wrapping my head around some problem with Core Data.
I have one user model in its own store that I do not have any control over, as it gets shipped with a framework. A Persistent Store Coordinator, Managed Object Model and Context for this model gets created automatically and cannot be touched. In it, this model has a single user entity
On the other hand, I have a properties model with a properties entity in it that I have complete control over. In there I store properties for some user entities in the other store. Both user and property entities have an id attribute similar to a foreign key.
This model has it's own Persistent Store Cordinator, Managed Object Model and Context.
What I now want is to have the associated user entity as an attribute of the properties entity so I might be able to bind to key-paths similar to myproperty.user.someValueOfTheUserEntity (I'm aware that myproperty might be an array when using fetched properties).
However, as cross-store relationships are not supported I thought of using a weak relationship via Fetched Properties. That one would just have to match the two corresponding id attributes. I have created a Fetched Property for the user in Xcode and the required accessors in my properties entity's class file (As suggested in other questions, I'm treating the values returned by the Fetched Property as an array).
However, I'm unable to set a destination entity for the Fetched Property in Xcode, as the target entity resides in a completely different store. Would I also have to define my user entity in the properties store? If so, how does Core Data know that that entity shall be fetched not from my properties store but from the users store?
Some threads mentioned using configurations for this, but I cannot find any documentation that goes further than mentioning "use configurations for this".
Can somebody enlighten me on how to set up cross-storage fetched properties? #
You can use several persistent stores that share the same data model:
Use single data model (xcdatamodeld) and add all your entities
Create configurations (Editor/Add Configuration) for each "logical set" of
entities that should be stored in separate store file
Assign (Drag) entities to appropriate configurations
Add configured persistent stores to your context (see below)
Configure fetched properties
// 1. Add "static", read-only store
[coordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:#"your static configuration name goes here..."
URL:storeUrl
options:#{
NSReadOnlyPersistentStoreOption: #(YES),
NSInferMappingModelAutomaticallyOption : #(YES)
}
error:&error];
// 2. Add "dynamic", writable content
[coordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:#"your dynamic configuration name goes here..."
URL:storeUrl
options:#{
NSMigratePersistentStoresAutomaticallyOption: #(YES),
NSInferMappingModelAutomaticallyOption : #(YES)
}
error:&error];

how can i update an object/entity that is not completely filled out?

I have an entity with several fields, but on one view i want to only edit one of the fields. for example... I have a user entity, user has, id, name, address, username, pwd, and so on. on one of the views i want to be able to change the pwd(and only the pwd). so the view only knows of the id and sends the pwd. I want to update my entity without loading the rest of the fields(there are many many more) and changing the one pwd field and then saving them ALL back to the database. has anyone tried this. or know where i can look. all help is greatly appreciated.
Thx in advance.
PS
i should have given more detail. im using hibernate, roo is creating my entities. I agree that each view should have its own entity, problem is, im only building controllers, everything was done before. we were finders from the service layer, but we wanted to use some other finders, they seemed to not be accessible through the service layer, the decision was made to blow away the service layer and just interact with the entities directly (through the finders), the UserService.update(user) is no longer an option. i have recently found a User.persist() and a User.merge(), does the merge update all the fields on the object or only the ones that are not null, or if i want one to now be null how would it know the difference?
Which technologies except Spring are you using?
First of all have separate DTOs for every view, stripped only to what's needed. One DTO for id+password, another for address data, etc. Remember that DTOs can inherit from each other, so you can avoid duplication. And never pass business/ORM entities directly to view. It is too risky, leaks in some frameworks might allow users to modify fields which you haven't intended.
After the DTO comes back from the view (most web frameworks work like this) simply load the whole entity and fill only the fields that are present in the DTO.
But it seems like it's the persistence that is troubling you. Assuming you are using Hibernate, you can take advantage of dynamic-update setting:
dynamic-update (optional - defaults to false): specifies that UPDATE SQL should be generated at runtime and can contain only those columns whose values have changed.
In this case you are still loading the whole entity into memory, but Hibernate will generate as small UPDATE as possible, including only modified (dirty) fields.
Another approach is to have separate entities for each use-case/view. So you'll have an entity with only id and password, entity with only address data, etc. All of them are mapped to the same table, but to different subset of columns. This easily becomes a mess and should be treated as a last resort.
See the hibernate reference here
For persist()
persist() makes a transient instance persistent. However, it does not guarantee that the
identifier value will be assigned to the persistent instance immediately, the assignment
might happen at flush time. persist() also guarantees that it will not execute an INSERT
statement if it is called outside of transaction boundaries. This is useful in long-running
conversations with an extended Session/persistence context.
For merge
if there is a persistent instance with the same identifier currently associated with the session, copy the state of the given object onto the persistent instance
if there is no persistent instance currently associated with the session, try to load it from the database, or create a new persistent instance
the persistent instance is returned
the given instance does not become associated with the session, it remains detached
persist() and merge() has nothing to do with the fact that the columns are modified or not .Use dynamic-update as #Tomasz Nurkiewicz has suggested for saving only the modified columns .Use dynamic-insert for inserting not null columns .
Some JPA providers such as EclipseLink support fetch groups. So you can load a partial instance and update it.
See,
http://wiki.eclipse.org/EclipseLink/Examples/JPA/AttributeGroup

Resources