agrestio / agrest

Server-side Java REST Framework for easy access to data graphs from various backends
https://agrest.io
Apache License 2.0
80 stars 34 forks source link

POST/PUT gets confused when relationship is passed as object #632

Closed andrus closed 1 year ago

andrus commented 1 year ago

To establish relationships on create / update, Agrest expects IDs to be passed for the relationship name properties. The result is establishing a connection between the object being saved and another object with the specified id. E.g.:

{ "name" : "N",
  "e2" : 1
}

Sometimes users want to use Agrest to create/update objects related to the root object. E.g.:

{ "name" : "N",
  "e2" : {"name" : "M"}
}

This results in an exception similar to the one below. While Agrest can not yet persist object graphs automatically, it should not get in the way of users trying to do it on their own. So when creating EntityUpdate objects out of request JSON, it should distinguish between raw IDs and full objects.

INFO org.apache.cayenne.log.JdbcEventLogger - SELECT "t0"."address", "t0"."name", "t0"."id_" FROM "e2" "t0" 
WHERE "t0"."id_" = ? [bind: 1->id_:'']
INFO org.apache.cayenne.log.JdbcEventLogger - *** error.
java.sql.SQLDataException: Invalid character string format for type INTEGER.
at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(SQLExceptionFactory.java:84)
...
at org.apache.cayenne.Cayenne.objectForPK(Cayenne.java:458)
at io.agrest.cayenne.processor.update.stage.CayenneMergeChangesStage.mergeChanges(CayenneMergeChangesStage.java:299)
at io.agrest.cayenne.processor.update.stage.CayenneMergeChangesStage.create(CayenneMergeChangesStage.java:116)
at io.agrest.cayenne.processor.update.stage.CayenneMergeChangesStage.merge(CayenneMergeChangesStage.java:70)
at io.agrest.cayenne.processor.update.stage.CayenneMergeChangesStage.execute(CayenneMergeChangesStage.java:58)
at io.agrest.cayenne.processor.update.stage.CayenneMergeChangesStage.execute(CayenneMergeChangesStage.java:44)
...
at io.agrest.processor.ExceptionMappingProcessorDecorator.execute(ExceptionMappingProcessorDecorator.java:21)
at io.agrest.runtime.DefaultUpdateBuilder.doSyncAndSelect(DefaultUpdateBuilder.java:180)
at io.agrest.runtime.DefaultUpdateBuilder.syncAndSelect(DefaultUpdateBuilder.java:151)