I am using Spring JDBC and I am a bit unsure on how to work with multiple one-to-many relations (or many-to-many). In this case I am injecting a repository into one of my resultsetextractors so that I can retrieve its associations. Is this the way to do it? Is it bad? Are there other better ways?
Note: I have left out the injection of repository
public class SomeResultSetExtractor implements ResultSetExtractor {
public Object extractData(ResultSet rs) throws SQLException, DataAccessException {
List result = new LinkedList();
while (rs.next()) {
SomeObject object = new SomeObject(rs.getString(1), rs.getLong(2));
result.add(object);
List<AnotherObject> otherObjects = anotherRepository.findAllById(object.getId);
object.setOtherObjects(otherObjects);
// and so on
}
return result;
}
}
Okey so after reading Dmytro Polivenok answer I have changed to RowMapper interface instead and I am currently using the other repositories to populate all associations like I show in my example. Is this a good way of doing it?
The @ManyToOne annotation is used to define a many-to-one relationship between two entities in Spring Data JPA. The child entity, that has the join column, is called the owner of the relationship defined using the @ManyToOne annotation.
This creates a one-to-many relationship between an author and book table. An author has many books. Using both @OneToMany and @ManyToOne makes this a bidirectional relationship. The mappedBy = "author" attribute tells us the book table is the owning side of the relationship.
ResultSetExtractor is an interface that is used to fetch the records from the database. It's a callback interface that is used by JDBC Template's query() method where we need to pass the instance of ResultSetExtractor in order to fetch the data.
I think a good practice for Spring JDBC and SQL queries in general is to use one query for each entity.
E.g. assume this model:
PaymentOption (customerId, cardnumber, cardtype, ...)
Customer 1---* Address
I would build 3 queries, 3 Daos, 3 ResultSetExtractors/RowcallbackHandlers:
If you would bake this in 1 query, you would have to build some logic to revert the cartasian product.
For many to many:
I would probably build:
Like this you could reuse ProductDao.readProducts for
I think that your code will work, but the concern here is about usage of ResultSetExtractor which is mainly for JDBC framework itself, and for most cases documentation recommends to use RowMapper.
So alternative approach would be to have method in your DAO that selects and maps parent object. Then for each object to invoke other Repository or private method that selects and maps child objects, and then to link child objects with parents based on your relationship type (one-directional or bidirectional). This approach may also allow you to control whether you want to load child objects or not.
For example, you may check Spring PetClinic application which has SimpleJdbcClinic class
If you can use other frameworks, you may consider mybatis, it is more about mapping and allows you to control your SQL code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With