we're building a REST-API using Spring MVC 3.2, Jackson 1.9.12, Hibernate 4.2.2.
Yesterday I needed to pass a small object graph to the API, which should get persisted in the database. It some kind of works and I could build workarounds for those problems, but I think there must be a nicer solution.
So here is what we have:
- Class
Bill
- Class
Contact
- Class
Address
- Class
Item
Relations are:
Bill
has twoOneToOne
relations toContact
. One calledsender
, one calledreceiver
.Bill
has aManyToOne
relation toItem
, calleditem
.Contact
has aOneToOne
relation toAddress
, calledaddress
.
(This may seem a bit dumb, but I left out some fields and other relations, to bring the problem to the point)
First Problem - Simple case - Overriding database entries:
Let's ignore all those dependencies and relations and just take the plain Bill
class. If there's an incoming JSON request which doesn't contain an object id everything works as expected and Spring/Hibernate creates a new entry in database:
{ ...
"createdAt":"2013-05-29"
}
But if I specify an id in the JSON request, Spring/Hibernate will update the row containing the given id:
{ ...
"id":"c5a562d0-c8ab-1c42-8399-080012345678"
"createdAt":"2013-05-29"
}
If I specify an id in the JSON request, but that id doesn't exist in database, it will create a new entry.
The code I use is nothing special. Here's the controller action:
@RequestMapping(value = "/create", method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.CREATED)
public Bill create(@RequestBody Bill bill) {
bill = service.createBill(bill);
return bill;
}
And the service method:
@PreAuthorize("isAuthenticated()")
@Transactional
public Bill createBill(Bill bill) {
bill = billDao.store(bill);
return bill;
}
As you can see, I'd like to use the /create
path to create new entries and not update already existing ones. As a workaround I could of course use setId(null)
in the first line of the controller action, but is there any nicer/better way?
Second Problem - Another id thing - How to correctly design entities?
We again have the object graph from above:
"bill":{ ...
"sender":{ ...
"address":{ ... }
},
"receiver":{ ...
"address":{ ... }
},
"item":{ ... }
}
There's a logical difference between Contact
(and Address
) and Item
:
- A
Contact
(andAddress
) consists of a bunch of new data. Means: The GUI will display a lot input fields, which the user has to fill in. - An
Item
is already in the database, and I basically would just need itsid
, not the whole object. This means: The GUI will display a dropdown list with all existingItem
s and the user has to choose one of them.
Now of course I'd like to use (and reuse) my entities, but my Bill
entity for example expects an Item
object, not an item_id
. As a workaround I could of course create another bean, which is nearly the same as the Bill
class, but instead of item
it contains an item_id
:
"the_new_special_bill_for_incoming_json":{ ...
"sender":{ ...
"address":{ ... }
},
"receiver":{ ...
"address":{ ... }
},
"item_id":{ ... }
}
So again, the same question: Is there a nicer/better way?
Thank you guys!