What's a good way to handle Generic Foreign Keys in JPA? - spring

We have an Spring 3.2, Hibernate 4.2 application.
Our application has an upload module, where you can basically upload all kinds of files. A file upload generates also a database entry:
id, directory, filename, mimeType, userId
So basically it should be possible to upload a file from everywhere in the application. And we don't want a new UploadEntity for every possible Entity. So we thought about using some kind of generic table for uploads:
id, directory, filename, mimeType, userId, FOREIGN_KEY
The problem of course is, that we can't set a concrete data type for this foreign key in JPA, because it can point to Entity A or B or C or ... We use UUID as keys in our application, so we thought about two solutions:
Make the foreignKey simply of type UUID and always save the foreign entity's id.
Make the foreignKey of type Object with a #ManyToOne annotation, but of course we can't provide a target entity for that.
But maybe there's some other much better/easier solution for this. What do you think?
I forgot to tell you, that each entity we use implements Persistable<UUID>, so is it possible to use this interface as type for the foreign key?
Btw: We need never to use the reference from UploadedItem -> SomeEntity. We only need the other way: SomeEntity -> UploadedItem.

Related

Retrieve the deleted record spring JPA

I am working on a spring application.
We have a specific requirement where when we get a specific event, we want to look it up in the DB. If we find the record in the DB, then we delete it from DB, create another event using the details and trigger it.
Now my concern is:
I do not want to use two different calls, one to find the record and another to
delete the record.
I am looking for a way where we can delete the record using a custom
query and simultaneously fetch the deleted record.
This saves two differnet calls to DB, one for fetch and another for delete.
What I found on the internet so far:
We can use the custom query for deletion using the annotation called #Modifying. But this does not allow us to return the object as a whole. You can only return void or int from the methods that are annotated using #Modifying.
We have removeBy or deleteBy named queries provided by spring. but this also returns int only and not the complete record object that is being deleted.
I am specifically looking for something like:
#Transactional
FulfilmentAcknowledgement deleteByEntityIdAndItemIdAndFulfilmentIdAndType(#Param(value = "entityId") String entityId, #Param(value = "itemId") String itemId,
#Param(value = "fulfilmentId") Long fulfilmentId, #Param(value = "type") String type);
Is it possible to get the deleted record from DB and make the above call work?
I could not find a way to retrieve the actual object being deleted either by custom #Query or by named queries. The only method that returns the object being deleted is deleteById or removeById, but for that, we need the primary key of the record that is being deleted. It is not always possible to have that primary key with us.
So far, the best way that I found to do this was:
Fetch the record from DB using the custom query.
Delete the record from DB by calling deleteById. Although, you can now delete it using any method since we would not be requiring the object being returned by deleteById. I still chose deleteById because my DB is indexed on the primary key and it is faster to delete it using that.
We can use reactor or executor service to run the processes asynchronously and parallelly.

Why is Hibernate #OnetoMany relationship required?

I have two entities Library and Books which are associated by Hibernate #OneToMany in a spring boot project. Fetching books in a particular library through the getter functions renders a LazyInitialisationException. The solution that I could find was making a query in the Books entity and fetching all the books corresponding to the library-id of the library. So, I was thinking why is oneToMany relationship required if we can just store a key corresponding to library in the Books table.
Simply storing a key doesn't provide any consistency assurances. Also, using defined OneToMany or ManyToOne you can also define the cascade types (you would only need to save the parent entity and then all the children would automatically be saved, in a single transaction).
The quick way to fix your problem would be to use FetchType EAGER, but I would recommend fixing whatever you have misconfigured.

DatastoreException: The given key doesn't have a String name value but a conversion to String was attempted

Changed #Id type from Long to String in GCP datastore using spring java Repository.
DatastoreDataException
org.springframework.cloud.gcp.data.datastore.core.mapping.DatastoreDataException: The given key doesn't have a String name value but a conversion to String was attempted
So Keys in datastore can either have the property id which is a number or the property name which is a string.
I included 2 screenshots of an example of each
Numeric id:
String name:
So when you say this:
Changed #Id type from Long to String in GCP datastore using spring java Repository.
What did you actually do?
It sounds like you just changed a model definition in your ORM. This doesn't actually change anything already stored in the datastore, it only impacts new entities going forward. So it sounds like, you're fetching entities with ids but your model definition is expecting them to have names.
You would have to have some kind of data migration job convert them all over. Convert isnt even the right word since changing the key to use name instead would just create a new entity. You would have to delete the old entities that use id in this process.
You would also have to update all other entities that have key properties to this kind too.
So we changed the Id from Long to String. And datastore table was already created with Long Id. so when we changed it we saw the above exception. By creating new table with String Id we resolved the issue.

Versionable Entities

I´m working on a project using ASPNET Boilerplate where some entities must be versioned, so they have an Id and a versionNumber, where the same entity can have several versions like:
Documents:[
{Document:{id:1, version:1}},
{Docuemnt:{id:1, version:2}}]
So my question is if there is an easy way of doing this, like the implementation of Soft Delete, where I can intercept the update method so it creates a new version.
You can override ApplyAbpConcepts in your DbContext to create a new entity when your Document entity is modified, then reload the original entity so that its changes are not saved.
CancelDeletionForSoftDelete does something similar.
But just doing this won't work because primary key is unique. You can create a composite key.
You will also have to handle relationships (i.e. foreign keys) to avoid linking to multiple versions.

Entity Framework: Implement interface when generating from database

I'm having a few tables on SQL Server, which have similar structure - int Id and string Value.
This tables linked to main table via foreign key, so I'm wrote a bit of logic for mapping a string values to id's in models in MVC Razor. This feature requires that models used as dictionary implement simple IKeyValue interface with Id and Value, but after updating model from database I can loose interface implementation from models and must write it again.
Any way to automate this?
Are you modifying the auto-generated file? If so, you should not do this, for the exact reason you describe in your question -- it will get overwritten.
All of the classes in the generated file should be partial. You can take advantage of this by creating another class (in a different file, but in the same project), make sure it has the same declaration (and namespace), and have it implement the interface. This way the class will implement the interface, but will not be overwritten the next time you refresh the schema from the database.

Resources