2016-12-23 6 views
0

Я разрабатываю API JAX-RS.Должно ли EntityManager # merge работать с не идентифицируемым объектом?

POST /myentities 
PUT /myentities/{myentityId} 

Мне понравилось это.

@PUT 
@Path("/{myentityId: \\d+}") 
@Consumes(...) 
@Transactional 
public Response updateMyentity(
    @PathParam("myentityId") final long myentityId, 
    final Myentity myentity) { 
    if (!Objects.equal(myentitiyId, myentity.getId())) { 
     // throw bad request 
    } 
    entityManager.merge(myentity); 
    return Response.noContent().build(); 
} 

Мне вдруг стало любопытно и допрошено самому себе.

Когда клиент вызывает после запроса

PUT /myentities/101 HTTP/101 
Host: .. 

<myentity id=101> 
</myentity> 

Возможно ли, что запрос обрабатывается, даже если нет ресурсов определены 101?

Я проверил тест.

acceptEntityManager(entityManager -> { 
    // persist 
    final Device device1 = mergeDevice(entityManager, null); 
    entityManager.flush(); 
    logger.debug("device1: {}", device1); 
    assertNotNull(device1.getId()); 
    // remove 
    entityManager.remove(device1); 
    entityManager.flush(); 
    assertNull(entityManager.find(Device.class, device1.getId())); 
    // merge again, with non existing id 
    final Device device2 = entityManager.merge(device1); 
    entityManager.flush(); 
    logger.debug("device2: {}", device2); 
}); 

Я обнаружил, что второе слияние работает и назначается новый идентификатор. Это нормально? Не должно EntityManager#merge лишить операцию?

ли это означает, что любой клиент может атаковать API, вызвав

PUT /myentities/<any number> 

?

ответ

0

Если я понимаю это право, то да, это то, как слияние должно работать. merge создает новый экземпляр вашего класса сущностей, копирует текущее состояние объекта, который вы предоставляете (в вашем случае device1, и добавляет этот экземпляр NEW к транзакции. Таким образом, управляется NEW, и любые изменения, которые вы вносите в старый экземпляр не обновляется в сделке и не будет распространяться на базу данных с помощью flush -. операций

Так что пока вы удалили device1 из базы данных с entityManager.remove(device1); на вызове
final Device device2 = entityManager.merge(device1); добавляет новую копию (с новым ID) в базу данных. Изменения, внесенные вами в device1, не отслеживаются в транзакции, поэтому они не отражаются в базе данных se столы один раз вы flush. Изменения в device2, с другой стороны, будут отслеживаться в транзакции.