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?
Related
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
Hi I was building an app and was wondering on how I can convert this query into a derived query method without using the annotation #Query:
SELECT address, COUNT(*) address FROM `employee` GROUP BY address ORDER BY address DESC LIMIT 5
I have tried it here is how I did it
List<Employee> countByAddressGroupByAddressByOrderByAddressDescLimit5();
This throws the following error
Invalid derived query! No property groupByAddressBy found for type String! Traversed path: Employee.address.
I was wondering if what am I doing wrong here thank you in advance.
I don't think query derivation supports group by.
You can't.
Derived queries don't support GROUP BY.
Derived queries are intended only for simple queries, where the mapping between a normal method name that you might choose independently from Spring Data and the query needed for implementation is obvious.
For more complex cases like the one you describe other mechanisms are available, like annotated or named queries. Nobody wants to use a method name like countByAddressGroupByAddressByOrderByAddressDescLimit5 anyway.
As others said, derived queries do not support this. There might be other reasons besides simply not being a 'practical' solution.
AFAIK derived query methods are restricted to retrieving instances just for the entity type managed by the repository (you can retrieve MyEntity, Optional<MyEntity>, Collection<MyEntity>, etcetera) or projections that match the fields/columns used for the managed entity.
When you use 'Group By', you break with this resultset structure, you usually have to explicitly indicate which columns you want to retrieve or which operations you want to perform on the grouped columns (which would be impossible using just a method name).
TL;DR
You can't easily indicate the columns you want to include in a 'Grouped By' query result, so no, I don't think there is a way to use this technique with 'Group By'.
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.
Suppose if I have 3 entities - User, Skills, Department
and I have repositories corresponding to all of them - UserRepository, SkillRepository, DepartmentRepository.
I understand that the relation mapping between entities i.e. one-one many-many should be specified in the respective entity classes. The question is I want to use all of the 3 entities in a query. How would I do it? A single repository is associated with only one entity right? So, how/where would I write it?
As there are many different ways to specify queries with Spring Data JPA there are various answers to this.
Maybe you don't have to. If entity A references B and you just want to get the Bs with your A you simply use your ARepository to load As and use object navigation to get your Bs. You might read up on eager and lazy loading for more information about how to control this.
If you want referenced entities in the where condition you can use property paths in your query method names: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-property-expressions
If you are using #Query annotations you can do (almost) whatever you want with JPQL. Among others, you may as well navigate properties to use them in where clauses.
In general, you'd put that query in the matching repository based on the primary entity returned.
Getting my feet wet with Grails, so please bear with me...
Just wondering if this is a good use of transient, or if there's a better way.
say I have
class Author {
String name
String favoriteBook
static transients = ["favoriteBook"]
etc.
"Favorite Book" is the title from the Book table of the a book published by the author. I have a database stored procedure (function) that I want to use to do this lookup. I don't want it persisted to the database, just evaluated on the fly when the Author list (and show) is executed. For the list, ideally it is sortable as well.
Note: using Oracle datbase
This obviously is not my real world example, I am actually working on extending a legacy database, and cannot touch that structure....I have a lot of stored procedures that can be utilized. So the question remains...I want my domain class to pull down a value from the database which is the result of a stored procedure.
I find examples on the web of using transients, but not in this way...am I misusing it? How do I utilize stored procedures within g&g and GORM?
I also find example of using stored procedures, like this one
http://www.craigburke.com/post/44771719252/oracle-stored-procs-in-grails
but missing how to implement this in the views...
tia...
K.
Instead of declaring it as a transient I would map it as a formula
class Author {
String name
String favoriteBook
static mapping = {
favoriteBook formula:'find_favorite_book(id)'
}
(or whatever the required SQL is to call your custom function).
Quoting from the linked documentation
Note that the formula expressed in the ORM DSL is SQL so references to other properties should relate to the persistence model not the object model.
i.e. if you need to refer to other properties in the formula then you have to use the database column names (some_property) rather than the property names (someProperty). If you don't want to have to guess the naming convention then you should consider making the property-to-column mapping explicit for any columns you want to use in the formula
static mapping = {
someProperty column:'my_unusual_column'
}