asyncer-io / r2dbc-mysql

Reactive Relational Database Connectivity for MySQL. The official successor to mirromutth/r2dbc-mysql(dev.miku:r2dbc-mysql).
https://r2dbc.io
Apache License 2.0
195 stars 21 forks source link

Not Able to access Id (auto generated field) post save operation #149

Closed bhishambajaj1999 closed 11 months ago

bhishambajaj1999 commented 11 months ago

return ordersRepository.save(orders) .flatMap(savedOrder -> { // Access the saved entity with the populated id Long orderId = savedOrder.getId(); log.info("OrderId.....{}", orderId); // Getting null here..

      // Perform operations on the id if needed
      // ...

      return Mono.just("Insert Successful"); // Return a success message
    })
    .doOnSuccess(successMessage -> log.info("Successfully Inserted"))
    .doOnError(error -> log.error("Failed to Insert", error));

}

@Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id", nullable = false) private Long id;

mysql: id bigint NOT NULL AUTO_INCREMENT, The field is getting persisted correctly in database, but I am not able to access it.

jchrys commented 11 months ago

Hello, @bhishambajaj1999. Unfortunately, I'm unable to replicate this problem in my current environment. Would it be possible for you to provide us with a reproducer?

bhishambajaj1999 commented 11 months ago

Hello, @jchrys , Please find additional info. public class Orders {

@Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id", nullable = false) private Long id;

@Column(name = "order_id", nullable = false) private String orderId;

@Column(name = "status", nullable = false) @Enumerated(EnumType.STRING) private OrderState status;

@Column(name = "type", nullable = false) @Enumerated(EnumType.STRING) private OrderType type;

@Column(name = "client_code", nullable = false) private String clientCode;

@Column(name = "billing_code", nullable = false) private String billingCode;

@Column(name = "pincode", nullable = false) private String pincode;

@Column(name = "address", columnDefinition = "json", nullable = false) @Type(type = "json") private Address address;

@Column(name = "lab_id") private Long labId;

@Column(name = "tenant_id", nullable = false) private String tenantId;

@Column(name = "contact_no", nullable = false) private String contactNo;

@Column(name = "contact_no_hashed", nullable = false) private String contactNoHashed;

@Column(name = "email_id") private String emailId;

@Column(name = "origin", columnDefinition = "json", nullable = false) @Type(type = "json") private Origin origin;

@Column(name = "referred_by", nullable = false) private String referredBy;

@Column(name = "is_deleted", columnDefinition = "bit(1)", nullable = false) private boolean isDeleted;

@Column(name = "attributes", columnDefinition = "json", nullable = false) @Type(type = "json") private OrderAttributes attributes; }

This is my R2dbcConfig @Bean public ReactiveTransactionManager transactionManager(ConnectionFactory connectionFactory) { return new R2dbcTransactionManager(connectionFactory); }

@Override @Bean @Primary public ConnectionFactory connectionFactory() { ConnectionFactoryOptions baseOptions = ConnectionFactoryOptions.parse(r2dbcProperties.getUrl()); ConnectionFactoryOptions ob = ConnectionFactoryOptions.builder().from(baseOptions) .option(USER, r2dbcProperties.getUsername()) .option(PASSWORD, r2dbcProperties.getPassword()) .build();

ConnectionFactory connectionFactory = ConnectionFactories.get(ob);
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
ConnectionPoolConfiguration.Builder builder = ConnectionPoolConfiguration.builder(
    connectionFactory);
R2dbcProperties.Pool pool = r2dbcProperties.getPool();
map.from(pool.getMaxIdleTime()).to(builder::maxIdleTime);
map.from(pool.getMaxLifeTime()).to(builder::maxLifeTime);
map.from(pool.getMaxAcquireTime()).to(builder::maxAcquireTime);
map.from(pool.getMaxCreateConnectionTime()).to(builder::maxCreateConnectionTime);
map.from(pool.getInitialSize()).to(builder::initialSize);
map.from(pool.getMaxSize()).to(builder::maxSize);
map.from(pool.getValidationQuery()).whenHasText().to(builder::validationQuery);
map.from(pool.getValidationDepth()).to(builder::validationDepth);

return new ConnectionPool(builder.build());

}

@Bean ConnectionFactoryInitializer initializer(ConnectionFactory connectionFactory) { ConnectionFactoryInitializer initializer = new ConnectionFactoryInitializer(); initializer.setConnectionFactory(connectionFactory); return initializer; }

@Override @Bean public R2dbcCustomConversions r2dbcCustomConversions() { List<Converter<?, ?>> converters = new ArrayList<>(); converters.add(new OrdersReadingConverter(objectMapper)); converters.add(new OrdersWritingConverter(objectMapper));

return new R2dbcCustomConversions(getStoreConversions(), converters);

}

Sharing Reading convertor public Orders convert(Row source) {

return Orders.builder()
    .id(source.get("id",Long.class))
    .orderId(source.get("order_id", String.class))
    .status(OrderState.valueOf(source.get("status", String.class)))
    .type(OrderType.valueOf(source.get("type", String.class)))
    .clientCode(source.get("client_code", String.class))
    .billingCode(source.get("billing_code", String.class))
    .pincode(source.get("pincode", String.class))
    .address(objectMapper.readValue(source.get("address", String.class), Address.class))
    .labId(source.get("lab_id", Long.class))
    .tenantId(source.get("tenant_id", String.class))
    .contactNo(source.get("contact_no", String.class))
    .contactNoHashed(source.get("contact_no_hashed", String.class))
    .emailId(source.get("email_id", String.class))
    .origin(objectMapper.readValue(source.get("origin", String.class), Origin.class))
    .referredBy(source.get("referred_by", String.class))
    .isDeleted(Boolean.TRUE.equals(source.get("is_deleted", Boolean.class)))
    .attributes(
        objectMapper.readValue(source.get("attributes", String.class), OrderAttributes.class))
    .build();

}

The requirement is to do operation on auto generated id, which I am not able to retrieve, but It is getting saved in database correctly. Currently I am handling this by explicitly calling
return databaseClient.sql("SELECT LAST_INSERT_ID()") .map((row, metadata) -> row.get(0, Long.class)) .one();

    In Jpa I am able to retrieve this auto generated Id implicitly, I am new to R2dbc not sure if it is supported implicitly, if yes not sure what is going wrong here.

    I am using spring boot **2.7.4**
   implementation("io.asyncer:r2dbc-mysql:0.9.4") => Driver for r2dbc
jchrys commented 11 months ago

Hello, @bhishambajaj1999. Thank you for providing the information. It appears that the details you've shared are not quite sufficient for me to replicate the issue in my own environment(https://stackoverflow.com/help/minimal-reproducible-example). However, it seems that the issue may be related to either spring-data-r2dbc or spring-data-relational. I would suggest considering reaching out to the respective project team.