'Spring JPA posting ManyToOne parent entity
here's the situation: Work object, some work a user can do. Users can also sign off on a work. So a very basic work object:
class Work (
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) var workId: Int,
var userId: Int,
...
var flags: Int,
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "signTargetUserId")
var signTargetUser: User?,
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "signedUserId")
var signedUser: User?
)
The User has a couple of things, this and that...:
class User(
@Id
val userId: Int,
val username: String,
val name: String,
val email: String,
@JsonIgnore
val password: String,
val flags: Int,
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "roleId")
var role: Role
)
Telling JPA about the user-role relationship is very handy, I hope we agree in that. When I get the user, I get the role too. The work-user relationship is also very nice, I like it. I get a work object, I know who's supposed to sign off on it (signTargetUser), and I also know this users role. Now, there's a controller to retrieve one or many work objects, and naturally the return type of these are Work or List<Work>. There has to be a function dealing with posting new Work entities. I have read it somewhere, that in a REST API it's nice if the entities travelling to and from are the same. So what structure does one have send to post a work? The same as one gets when querying one. Na then:
fun createWork(@RequestBody work: Work, authentication: Authentication): ResponseEntity<Any> {
This is very handy, I really like that, except that it doesn't work at all. Now the request body must be a valid Work object that sounds sweet with the validation for like a ms, but then it doesn't. It requires 2 User objects, one at signTargetUser and one at signedUser. To make it worse, these users must have Role objects hanging on them. To make it even worse, the User objects must have a non-null password property. Obviously I don't even know that, this is now way out of hand. All I want to do is insert a Work object, knowing the signTargetUserId if any.
I see a solution in 2 steps, but i don't like it at all:
- First I need to create another class (
WorkIncoming) only to describe the structure of the object coming in in the post, but this time without the ManyToOne relationships. But then when you read back the work you created, you'd get a different structure.WorkIncomingin andWorkout. Not to mention the semi-useless new class that would mostly be a bad repetition of the first one. If I add or change a field, do i need to change 2 files? Seriously? - Obviously the original repository is dealing with
Workclasses, so it won't be able to handleWorkIncomingtype: new repository then. Again, total code duplication, maintenance blah blah. I'm not even sure now how the JPA would feel about 2 entities referencing the same table.
So what's the real solution here? How do real people do that? I'm out of ideas here. This solution that I have just described is terribly low-tech, that can't be it!
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
