micronaut-data icon indicating copy to clipboard operation
micronaut-data copied to clipboard

Id column in table must be first to make @GeneratedId work with JdbcRepositories

Open zoltan-toth-mw opened this issue 2 years ago • 0 comments

Expected Behavior

I altered my table and now the primary key is not in the first column in the table. I'd expect that position of the ID column in the table does not matter and the ResultSet of the insert action, with the generated id is properly read.

Actual Behaviour

Value of the generated id is looked for at the first position from the ResultSet, but the id is not at the first position in the result set. An exception is thrown as the first column has a different type than the id column.

Caused by: io.micronaut.data.exceptions.DataAccessException: Error reading object for index [1] from result set: Bad value for type int : example.com
	at io.micronaut.data.jdbc.mapper.ColumnIndexResultSetReader.exceptionForColumn(ColumnIndexResultSetReader.java:232)
	at io.micronaut.data.jdbc.mapper.ColumnIndexResultSetReader.readInt(ColumnIndexResultSetReader.java:129)
	at io.micronaut.data.jdbc.mapper.ColumnIndexResultSetReader.readInt(ColumnIndexResultSetReader.java:41)
	at io.micronaut.data.runtime.mapper.ResultReader.readDynamic(ResultReader.java:111)
	at io.micronaut.data.jdbc.mapper.ColumnIndexResultSetReader.readDynamic(ColumnIndexResultSetReader.java:69)
	at io.micronaut.data.jdbc.mapper.ColumnIndexResultSetReader.readDynamic(ColumnIndexResultSetReader.java:41)
	at io.micronaut.data.jdbc.operations.DefaultJdbcRepositoryOperations$JdbcEntityOperations.execute(DefaultJdbcRepositoryOperations.java:958)

An easy solution would be to use identity.getName() to get the id value from the ResultSet instead of the fixed 1. Problematic code part:

// DefaultJdbcRepositoryOperations.java
 if (hasGeneratedId) {
                    try (ResultSet generatedKeys = ps.getGeneratedKeys()) {
                        if (generatedKeys.next()) {
                            RuntimePersistentProperty<T> identity = persistentEntity.getIdentity();
                            Object id = columnIndexResultSetReader.readDynamic(generatedKeys, 1, identity.getDataType());
                            BeanProperty<T, Object> property = (BeanProperty<T, Object>) identity.getProperty();
                            entity = updateEntityId(property, entity, id);
                        } else {
                            throw new DataAccessException("Failed to generate ID for entity: " + entity);
                        }
                    }
                }

Steps To Reproduce

create table example
(
    domain             varchar(128) not null,
    id                 serial  primary key,
    geoname_id         integer
);
@MappedEntity
@Data
public class Example {

    @Id
    @GeneratedValue
    private Integer id;
    private String domain;
    @Nullable
    private Integer geonameId;
}

@JdbcRepository(dialect = POSTGRES)
public interface ExampleRepo extends PageableRepository<Example, Integer> {

}

Environment Information

Jdk17

Example Application

No response

Version

3.5.3

zoltan-toth-mw avatar Jul 20 '22 10:07 zoltan-toth-mw