简体   繁体   中英

How can I delete element from collection using stateless session? (ConstraintViolationException)

I have

@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
public Linf getLinf() {
    return linf;
}

and

@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, targetEntity = MessageEntry.class)
public Set<MessageEntry> getMessageEntries() {
    return messageEntries;
}

I need to remove single messageEntry from database. If I say sess.delete(messageEntry), then I get index exception since its in Linf.messageEntries collection. Stateless session can't load collection, so I have to load elements of Linf.messageEntries mannually and then remove one of them:

            List linfs = sess.createQuery(
                    "SELECT l FROM Linf l " +
                            "JOIN l.messageEntries e WHERE e=:e")
                    .setParameter("e", messageEntry).list();

            if (linfs.size()>1) throw new RuntimeException();

            Linf linf = (Linf) linfs.get(0);

            List<MessageEntry> curEntries =
                    sess.createQuery(
                            "SELECT e FROM Linf l " +
                            "JOIN l.messageEntries e WHERE l=:l")
                            .setParameter("l", linf).list();

            for (int i = 0; i < curEntries.size(); i++) {
                if (curEntries.get(i).getId().equals(messageEntry.getId())) {
                    curEntries.remove(i);
                    break;
                }
            }

            Set<MessageEntry> cur = new HashSet<MessageEntry>();
            cur.addAll(curEntries);
            linf.setMessageEntries(cur);

            messageEntry.setLinf(null);
            sess.update(messageEntry);
            sess.update(linf);
            sess.delete(messageEntry);

I get ConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails ( db . linf_messageentry , CONSTRAINT FK5039A8B5E770809A FOREIGN KEY ( messageEntries_id ) REFERENCES messageentry ( id )). How can I perform this task? Thank you.

Your mapping is wrong. Instead of having a bidirectional one-to-many association, using a foreign key in MessageEntry, you have a OneToMany association using a join table ( linf_messageentry ), and another, distinct, ManyToOne association using a foreign key.

The one side must be marked as the inverse of the many side, using the mappedBy attribute:

// This is the owner side of the association, because it doesn't have 
// the mappedBy attribute.
// it uses a join column by default
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
public Linf getLinf() {
    return linf;
}

and

// This is the inverse side, because it has the mappedBy attribute
// since it's mappedBy linf, hibernate uses the same mapping as the one
// described on the linf property: a join column
@OneToMany(mappedBy = "linf", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
public Set<MessageEntry> getMessageEntries() {
    return messageEntries;
}

Also, note that:

  • the targetEntity attribute is completly redundant: Hibernate knows the target entity from the type of the collection: Set<MessageEntry>
  • cascade = CascadeType.ALL on a ManyToOne doesn't make much sense. If you delete a MessageEntry, you don't want its Linf to be deleted.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM