I've put a derived query on a CrudRepository<Customer, Long> that should delete all entities with a given businessId (which is not the primary key but just another, non-unique column), of which there can be many.
In my SpringDataJdbcTest test, I first save 2 customers with the same businessId.
Then, I want to call the following method on the CrudRepository:
fun deleteAllByBusinessId(businessId: Long)
But it gives me:
org.springframework.dao.IncorrectResultSizeDataAccessException: Incorrect result size: expected 1, actual 2
at org.springframework.dao.support.DataAccessUtils.nullableSingleResult(DataAccessUtils.java:100)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.queryForObject(NamedParameterJdbcTemplate.java:244)
It seems Spring Data Jdbc first wants to determine if there's a unique entity with that business Id, but of course, there are 2.
Could it be that support for such a derived delete query doesn't work correctly? I use Spring Data JDBC 2.3.5.
You are right, derived delete queries don't work yet. See https://github.com/spring-projects/spring-data-relational/issues/771
Related
I have 5 similar tables from which I need to execute a same query and fetch data in pages. I have used polymorphic queries (have super abstract class and used #Inheritance to fetch all rows automatically)
But this approach has problems as noted here: Database pressure on Polymorphic queries
The issue is that the queries use union all which makes DB to search through millions of rows just to get 500 results. So instead I want to execute this serially.
When I execute the method JPA will go to first table; fetch data in pages; if the data fetching is complete then go to second table and so on...
Right now with union, I have ton of pressure on database. With this new approach, I could have less pressure as only one table is accessed at once.
I do not know a way to do this without changing the setup I have right now. For example right now I have it like this:
public interface OhlcDao extends JpaRepository<AbstractOhlc, OhlcId> {
Slice<OhlcRawBean<? extends OhlcBean>> findByIdSourceIdAndIdTickerIdIn(
String sourceId,
Set<String> tickerId,
PageRequest pageRequest
);
}
The method uses union to fetch data which I do not like.
Is there a way to make this work in JPA or Hibernate by changing any internal code (aka without changing my setup, so similar method does not use unions)
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.
I am using Spring Data JDBC 2.0.5 (as pulled in by Spring Boot 2.3.5) on top of Postgres 11.10.
In our domain model we have an aggregate root that looks something like the following:
#Table(...)
class OurAggregateRoot {
#MappedColumn(...) // 1:1 relationship
private final ReallyLongClassNameForThisEntity reallyLongClassNameForThisEntity;
}
#Table(...)
class ReallyLongClassNameForThisEntity {
#MappedColumn(really_long_class_name_id) // 1:1 relationship
final AnotherReallyLongClassName anotherReallyLongClassName;
}
Given that we have three tiers of relationships and long class names we've run into a situation where a column alias in the query that was generated when calling CrudRepository::findById exceeded the character limit as set by PostgreSQL. E.g. the column alias for the identifier AnotherReallyLongClassName uses to reference its parent entity would be reallyLongClassNameForThisEntity_anotherReallyLongClassName_really_long_class_name_id.
Is there something we can do to safeguard against this aside from renaming class/field/column names and limiting the number of nested relationships within an aggregate root? Trying to change the character limit on Postgres alias names doesn't appear to be an easy option for us.
There is no direct way to avoid this.
Things that help are: using shorter names for columns as you said and taking a hard look at your aggregates: Is it really appropriate to have such deeply nested aggregates?
I have an Entity that has four properties, (vehicle, unit, date and id). Primary key is the ID.
I want to delete rows from the database based on the vehicle list provided to me via a request body.
How can I take all the lists and use them to delete data from the database at once?
You can create a "delete...By" query in your Entity repository that takes a List of Vehicle as a parameter and deletes all entities that their Vehicle is contained in that List.
Something like this should work:
void deleteAllByVehicle(List<Vehicle> vehicles);
The documentation contains more options:
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods
you can use JPQL to provide custom query
#Query(delete from Entity e where e.idvehicle = :id)
void deleteByVehicle(#Param("id") int idvehicle);
now you can just pass the id of the Vehicle like that:
deleteByVehicle(vehicle.getId());
I have a Spring Boot application and I am using Spring Data JPA to query a PostgreSQL database.
I have a column of List type in my database. Now I need a query to search all those rows where my input parameter is present in this list.
eg. I have a column of type List containing any of these values: ["cat","dog","cow"].
I need to find all those rows where "cat" is one among the list.
Can you help me with the format of this query? Thanks in advance.
From what I could understand, you have a DB table, let's say Sample. Now this table has multiple columns with one column whose values can be either of "cat","dog","cow". Let's assume the column name to be 'sampleName'.
So, in your code you must be having an #Entity class for Sample with #Column sampleName, and a corresponding JPA repository - SampleRepository.
Now, the code for requirement should look like as shown below:
public interface SampleRepository extends JpaRepository<Sample, Long> {
Optional<Sample> findBySampleName(String sampleName);
}
In above JPA repository, I have assumed that you have an #Id field of type Long in your entity Sample. Also, I have made use of method-name strategy. Spring boot will automatically translate this method name to a SQL query at run time like - SELECT * FROM sample WHERE sampleName = 'cat'. This value cat will be provided to your repository method as an argument from #Service layer.
Hope this helps!
In addition to this, you can also choose to use the native query approach. Please refer - https://www.baeldung.com/spring-data-jpa-query for more details.