ebean-orm / ebean-orm/ebean

Feature Request: Insert with InsertOptions expose affected row count

Open
#3,875 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Java
Stars
1.5k
Forks
267
Avg merge
3d 20h
Merged PRs (30d)
5

Description

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.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing the database.insert(bean, InsertOptions...) entry point and how the JDBC insert result is currently handled. Expose the affected row count for ON_CONFLICT_NOTHING, with completion demonstrated by distinguishing 1 inserted row from 0 skipped rows in the existing insert behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, sql
Domain
backend, databases
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.