Skip to content

Feature Request: Insert with InsertOptions expose affected row count #3875

Description

@mageddo

Expected behavior

When using insert() with InsertOptions, especially with ON CONFLICT DO NOTHING, I would like to obtain the number of affected rows.

For example, an API equivalent to:

int affectedRows = database.insert(bean, InsertOptions.ON_CONFLICT_NOTHING);

This would allow applications to atomically determine whether the row was actually inserted:

int affectedRows = database.insert(
  bean,
  InsertOptions.ON_CONFLICT_NOTHING
);

boolean inserted = affectedRows > 0;

A different method/signature would also work if changing the existing insert() API is undesirable.

The important part is exposing the JDBC/database affected row count when using InsertOptions.

This is particularly useful for implementing atomic createIfAbsent() operations without requiring:

  • a separate SELECT / exists() before the insert;
  • exception-based duplicate detection;
  • or manually written SQL.

For PostgreSQL, for example:

INSERT INTO fruit (...)
VALUES (...)
ON CONFLICT (...) DO NOTHING

naturally provides the required information:

  • 1 affected row when the row was inserted;
  • 0 affected rows when the conflict caused the insert to be skipped.

Actual behavior

Currently:

database.insert(bean, InsertOptions.ON_CONFLICT_NOTHING);

returns void.

Therefore, although Ebean correctly generates and executes INSERT ... ON CONFLICT DO NOTHING, the caller cannot determine whether:

  • the row was inserted; or
  • the insert was skipped because of a conflict.

This makes it impossible to implement an atomic operation such as:

boolean createIfAbsent(Fruit fruit)

using the generated Ebean insert alone.

Steps to reproduce

var options = InsertOptions.builder()
  .onConflictNothing()
  .build();

var fruit1 = new Fruit();
fruit1.setId("apple");

database.insert(fruit1, options);

// Insert the same unique/primary-key value again

var fruit2 = new Fruit();
fruit2.setId("apple");

database.insert(fruit2, options);

Both calls return void, so there is no way for the caller to distinguish the first insert from the second no-op.

Ideally, the affected row count should be exposed so the first operation can report 1 and the second 0.

PS: I also consider it useful in operations like, update, save, merge, etc.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions