orphanRemoval with "on delete cascade"; also handling an overlapping mapping

View: New views
3 Messages — Rating Filter:   Alert me  

orphanRemoval with "on delete cascade"; also handling an overlapping mapping

by Ernie Rael :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Given table A with primary key ID, and table B with A_ID FOREIGN KEY(A_ID) REFERENCES A(ID) ON DELETE CASCADE. And
    @Entity
    public class A {
        @OneToOne(orphanRemoval=true)
        private B b;
    }

When I do
    A.setB(null);
    commit();
There is a "DELETE FROM B WHERE A_ID = ?" sent to the database, though this is not needed because of the constraint with on delete cascade. Is there anyway to get rid of the extraneous delete? In the spec, around the end of 2.9, it says

    The persistence provider handles the object/relational mapping of the
    relationships, including their loading and storing to the database as
    specified in the metadata of the entity class, and the referential
    integrity of the relationships as specified in the database (e.g., by
    foreign key constraints).

which could be interpreted to mean that the provider does not have to send the delete statement. I'm using eclipselink-2.0 M7.


Another question, loosely related. I've got two tables/entities CHART and EVENT which are in an n:m relationship; each table has a primary key ID. The join table is CHART_EVENT with CHART_ID and EVENT_ID. There are also several tables/entities that have "@EmbeddedId ChevPK chevPK" where ChevPK references CHART_EVENT with EVENT_ID. For example Aspectdisplay below. The Chart entity maps both the the join table and the m:n relationship. Note that the remove method removes from both mapped collections; this works, but there are two DELETE statements sent to the database, anyway to prevent this? Conceptually I'm not sure what to right thing to do with the addEvent method; currently I add the event to the m:n, which assigns keys and add to the join table, and then do a em.refresh(chart), anything better to do?


    @Entity
    @Table(name = "CHART", catalog = "", schema = "ERNIE")
    public class Chart implements Serializable {
        private static final long serialVersionUID = 1L;
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Basic(optional = false)
        @Column(name = "ID", nullable = false)
        private Integer id;

        @OneToMany(mappedBy = "chart", orphanRemoval=true)
        private Collection<ChartEvent> chartEventCollection;

        @ManyToMany
        @JoinTable(name = "CHART_EVENT" ,
                inverseJoinColumns = {
                    @JoinColumn(name = "EVENT_ID",
                            referencedColumnName = "ID", nullable = false)})
        private Collection<Event> eventCollection;

        boolean addEvent(Event e) {
            return getEventCollection().add(e);
        }

        boolean removeEvent(Event e) {
            ChartEvent ce = new ChartEvent(getId(), e.getId());
            getChartEventCollection().remove(ce);
            return getEventCollection().remove(e);
        }



    @Entity
    @Table(name = "ASPECTDISPLAY", catalog = "", schema = "ERNIE")
    public class Aspectdisplay implements Serializable {
        private static final long serialVersionUID = 1L;
        @EmbeddedId
        protected ChevPK chevPK;

        @Basic(optional = false)
        @Lob
        @Column(name = "DAT", nullable = false)
        private AspectdisplayData dat;

        @OneToOne(optional = false)
        @JoinColumns({
            @JoinColumn(name = "CHART_ID", referencedColumnName = "CHART_ID",
                nullable = false, insertable = false, updatable = false),
            @JoinColumn(name = "EVENT_ID", referencedColumnName = "EVENT_ID",
                nullable = false, insertable = false, updatable = false)})
        private ChartEvent chartEvent;

Re: orphanRemoval with "on delete cascade"; also handling an overlapping mapping

by James Sutherland :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

For using delete cascade in the database you could,
- Remove the orphanRemoval=true, since you are deleting it on the database,
- Or, remove the delete cascade on the database, as you have orphanRemoval=true,
- Or, live with the duplicate deletion.

You may also wish to log an bug/ehancement request for EclipseLink to have some enhanced support for this.


I'm not sure I understand you second issue.  You seem to have mapped the m-m join table as an Entity ChartEvent, but also defined a m-m for it.  I would recommend not doing both, only mapping the 1-m to the ChartEvent object, as you can then access the event from the join object.  You can join-fetch or batch-read the event if efficiency is your concern.

You could also make the m-m read-only in EclipseLink using a DescriptorCustomizer set the ClassDescriptor mapping to be readOnly.

Re: orphanRemoval with "on delete cascade"; also handling an overlapping mapping

by Ernie Rael :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Thanks for the comments.

> For using delete cascade in the database you could,
> - Remove the orphanRemoval=true, since you are deleting it on the database,

The problem with getting rid of the orphanRemoval=true is that the perstence context and 2nd level cache are out of sync with the DB.  Manually evicting stuff from the cache is a hassle.

> - Or, remove the delete cascade on the database, as you have orphanRemoval=true,

I guess I have an emotional attachment to the database constraints :-)

> - Or, live with the duplicate deletion.

It's not a performance thing in this case, but the issue could arise elsewhere at some point.

> You may also wish to log an bug/ehancement request for EclipseLink to have some enhanced support for this.

I'll do that.


> I'm not sure I understand you second issue.  You seem to have mapped the m-m join table as an
> Entity ChartEvent, but also defined a m-m for it.

Yes, that what I've got now.

> I would recommend not doing both, only mapping the 1-m to the ChartEvent object, as you can then
> access the event from the join object.
> You can join-fetch or batch-read the event if efficiency is your concern.

I guess I really like the idea of adding an Event to a Chart, persisting the chart and having things done in the right order and the join table updated, for example logging shows:
    [EL Fine]: Connection(11616335)--INSERT INTO ERNIE.CHART (NAME) VALUES (?) bind => [Narrow Orb]
    [EL Fine]: Connection(11616335)--values IDENTITY_VAL_LOCAL()
    [EL Fine]: Connection(11616335)--INSERT INTO CHART_EVENT (EVENT_ID, Chart_ID) VALUES (?, ?) bind => [907, 2287]
then em.find the created ChartEvent and add it to the chartEventcollection or simply do chart.refresh(). The other way around seems slightly more complex in java code.


> You could also make the m-m read-only in EclipseLink using a DescriptorCustomizer
> set the ClassDescriptor mapping to be readOnly.
Jeez, something else to learn ;) Thanks for the pointer, I'll have to check this stuff out. I'd be inclined to make the 1-m to ChartEvent readonly. I'm a novice, is there some reason to do it the other way around?