0

I have a User class, a Conversation class and a Message class. A user can be a sender and a receiver. I don't know how to set up Cascade types, if my goals are:

  • if a user is deleted keep his/her messages and his/her conversations
  • if both users are deleted delete the conversation and the messages
  • if a user delete his/her last message from the conversation keep the conversation with the other users message
  • if a user deletes a conversation delete just the user from the conversation but keep the conversation itself and the other user with all of the messages
  • just after both users were deleted delete conversations with no users and the messages for these conversations

It seems to me, I can set all CascadeType except CascadeType.Delete everywhere. Have to I check every deletation manually. I think I can't set CascadeType.Delete for example on user's messages because I want to keep them even I delete the user, and delete them just if I delete all participant of the conversation. I'm not sure but I think I can't set orphanremoval on user's message, because if I delete a user it will clear the list of the messages and it will remove the messages.

@Entity
class User {

    @Id
    @GeneratedValue
    val id: Long = 0

    @OneToMany(mappedBy = "reviewer")
    lateinit var conversations: List<Conversation>

    @OneToMany(mappedBy = "sender")
    lateinit var sentMessages: List<Message>

    @OneToMany(mappedBy = "receiver")
    lateinit var receivedMessages: List<Message>
}

@Entity
class Conversation {

    @Id
    @GeneratedValue
    val id: Long = 0

    @OneToMany(mappedBy = "conversation")
    lateinit var messages: List<Message>
}


@Entity
class Message {

    @Id
    @GeneratedValue
    val id: Long = 0

    @ManyToOne
    lateinit var conversation: Conversation

    @ManyToOne
    lateinit var sender: User

    @ManyToOne
    lateinit var receiver: User

    lateinit var message: String
}
user3057944
  • 701
  • 1
  • 8
  • 19

1 Answers1

0

The non-trivial rules you set up are too much for Hibernate to handle out of the box.

I recommend using the DDD concept of Aggregates and Aggregate roots to decompose your model use cascade inside the Aggregates and communicate with events between the two.

I see two Aggregates: User and Conversation. The Conversation aggregate consists of the Conversation as Aggregate Root and the Messages as additional entities.

Remove the list of Messages from the User and provide finder-methods in the ConversationRepository instead.

All the logic you describe goes in methods in User, UserRepository, Conversation, and ConversationRepository. The User* classes may delegate to the ConversationRepository for manipulating Conversations and Messages.

With this approach implementing the desired logic should be easier to implement, test, and understand. Many steps might actually be easier (and possibly faster) implemented using direct SQL instead of JPA. Of course, you'll have to take care that JPAs 1st-level-cache doesn't get stale.

Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
  • Thank you! So this logic is too complex for impelment it with hibernate, and I've to implement it somewhere in my business logic. – user3057944 Sep 10 '18 at 06:41