Home > Blockchain >  How does repository.save() work, and how to test unique constrains in Spring data JPA
How does repository.save() work, and how to test unique constrains in Spring data JPA

Time:02-17

I have a table "MyService" with unique constraints on two columns (namespace and name) and Id is the pk. | name | type | | -------- | ------------- | | id | Long | | namespace | string | | name | string | | value | string |

I want to write unit test to make sure user cannot insert new row with the same (namespace and value). So I code like this:

@Test
public void insertDuplicateTest()  {
    Service service1 = Service.builder().namespace("ns").name("n1").value("v1").build();
    repository.saveAndFlush(service1);
    Service service2 = Service.builder().namespace("ns").name("n1").value("v2").build();
    repository.saveAndFlush(service2);
}

I have two questions:

  1. From my understanding jparepository will insert if the entity does not exist, and merge if is. So why this raise an error:

org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [uk5pg2rvcx3fsu5dctsm3pyqkh6]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement

  1. How can I complete this unit test to check there is an error or exception?

CodePudding user response:

From my understanding jparepository will insert if the entity does not exist, and merge if is. So why this raise an error:

It will but an entity existing means an entity with the same primary key existing, other columns/attributes are not important (no matter if unique or not) for that.

The exception is thrown as JPA tries to insert it (as the primary does not exist already) but it fails as the UNIQUE constraint is violated.

If you use @GeneratedValue for your primary key, it will not merge newly created object but assign them a new id and insert them (failing because of the UNIQUE constraint).

If you want to merge objects, you need to either use different (non-@GeneratedValue) primary keys or modify existing objects (like service1).

How can I complete this unit test to check there is an error or exception?

If you expect an exception, just use assertThrows:

@Test
public void insertDuplicateTest()  {
    Service service1 = Service.builder().namespace("ns").name("n1").value("v1").build();
    repository.saveAndFlush(service1);
    Service service2 = Service.builder().namespace("ns").name("n1").value("v2").build();
    assertThrows(DataIntegrityViolationException.class, () -> repository.saveAndFlush(service2);
}
  • Related