These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 9 posts ] 
Author Message
 Post subject: CascadeType.ALL does not work when deleting
PostPosted: Fri Feb 15, 2008 9:11 pm 
Newbie

Joined: Mon Dec 17, 2007 11:50 am
Posts: 14
Hi,

I have two classes, Edge and Lane,

Edge looks like
Code:
@Entity
@Table(name="edges")
@SequenceGenerator(name="SEQ_EDGE", sequenceName="edges_id_seq")
public class Edge extends EWorldElement implements Serializable {
   
   @Id
   @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_EDGE")
   private int id;
   
   @OneToMany(fetch=FetchType.EAGER)
   @JoinColumn(name="edge")
   @Cascade({org.hibernate.annotations.CascadeType.ALL})
   @IndexColumn(name = "indexinlist", base=0)
   private List<Lane> lanes;

[...]
}


When I delete the edges, and persist them again, the lanes are not deleted in the database (with
Code:
q = this.session.createQuery("delete Edge");
   q.executeUpdate();   
)

When I do the following:
Code:
q =this.session.createQuery("delete Edge");
q.executeUpdate();
q =this.session.createQuery("delete Lane");
q.executeUpdate();         


the lanes are removed from the database, but they are still connected to the session. When I try to save the edges again, Hiberante only wants to update the lanes, because it thinks, that they are still there. As there is no database entry any more, I receive this error:
org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1. In any case first, I want to delete all edges and lanes, and afterwards persist them again. Anyone an idea for that?
Thanks![/code]


Top
 Profile  
 
 Post subject:
PostPosted: Sat Feb 16, 2008 5:27 am 
Newbie

Joined: Wed Jan 16, 2008 2:53 am
Posts: 5
hi
test this:
@OneToMany( cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
i think it's correct


Top
 Profile  
 
 Post subject:
PostPosted: Sat Feb 16, 2008 5:29 am 
Expert
Expert

Joined: Thu Jul 05, 2007 9:38 am
Posts: 287
use session.delete and cascade should work.

When you execute a query hibernate has no way which entities where affected.

Jens

_________________
Please rate useful posts.


Schauderhaft: Softwaredevelopment, Projectmanagement, Qualitymanagement and all things "schauderhaft"


Top
 Profile  
 
 Post subject:
PostPosted: Sat Feb 16, 2008 7:59 am 
Newbie

Joined: Mon Dec 17, 2007 11:50 am
Posts: 14
schauder wrote:
use session.delete and cascade should work.

When you execute a query hibernate has no way which entities where affected.

Jens


Following schauder's did not work completely. Then I tried this:

in class Edge:
Code:
@OneToMany
@JoinColumn(name="edge")
@IndexColumn(name = "indexinedge", base=0)
@Cascade({CascadeType.ALL})
private List<Lane> lanes;


Code:
And in my persistence class:
for(Edge e: db.getEdges()) {
    this.session.delete(e);
}


When I save all objects newly, I still get: org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1

When I look in the database log (Postgre), I can see,

2008-02-16 12:49:44 LOG: execute <unnamed>: delete from lanes where id=$1
2008-02-16 12:49:44 DETAIL: parameters: $1 = '27226'

but in the following re-save:
2008-02-16 12:49:44 LOG: execute S_34: update lanes set maxSpeed=$1, minSpeed=$2 where Id=$3
2008-02-16 12:49:44 DETAIL: parameters: $1 = '100', $2 = '0', $3 = '27226'

without an insert before, of course this crashes. I thougth, with delete() and cascade, the session should know about the deleting. Deleting the lanes explicitly with session.delete(lane) leads to the same error.

Any idea, hint?


Top
 Profile  
 
 Post subject:
PostPosted: Sun Feb 17, 2008 8:22 am 
Expert
Expert

Joined: Thu Jul 05, 2007 9:38 am
Posts: 287
Make sure that your objects (edges and lanes) are detached AND their IDs are null, so hibernate recognizes them as nes instances.

You can check if the object is detached or not by calling session.contains()
and you can detach it via evict.

HTH
Jens

_________________
Please rate useful posts.


Schauderhaft: Softwaredevelopment, Projectmanagement, Qualitymanagement and all things "schauderhaft"


Top
 Profile  
 
 Post subject:
PostPosted: Mon Feb 18, 2008 6:59 pm 
Newbie

Joined: Mon Dec 17, 2007 11:50 am
Posts: 14
schauder wrote:
Make sure that your objects (edges and lanes) are detached AND their IDs are null, so hibernate recognizes them as nes instances.

You can check if the object is detached or not by calling session.contains()
and you can detach it via evict.

HTH
Jens


Dear Jens,
this works almost perfectly for all my classes. However I have a class
Event with an attribute Location:

@OneToOne(fetch=FetchType.EAGER)
@JoinColumn(name="location") @Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE, CascadeType.ALL})
protected Location location;

Location has a collection of the above mentioned Edges:

@ManyToMany(fetch=FetchType.EAGER)
@JoinTable(
name="location_edge",
joinColumns={@JoinColumn(name="location")},
inverseJoinColumns={@JoinColumn(name="edge")}
)
@Cascade({CascadeType.SAVE_UPDATE, CascadeType.PERSIST})
protected List<Edge> edges;

I delete all objects as you explained before (truncate in db and set id to 0, evict is not necessary, as a new session was just opened before).
Now, after deleting and saving, when I reload the data from the db, Hibernate somehow does not use the Location that was saved before, but creates (! without having any save() in this transaction) a new db entry. This really looks odd to me, as I have two subclasses of Location, and it works for one, but not for the other. The only difference regarding relations is, that the one, for that it works, has several Edges, the one, for that it doesn't work, can only have one.

Any help is welcome


Top
 Profile  
 
 Post subject:
PostPosted: Tue Feb 19, 2008 3:47 am 
Expert
Expert

Joined: Thu Jul 05, 2007 9:38 am
Posts: 287
Can you post some code?

_________________
Please rate useful posts.


Schauderhaft: Softwaredevelopment, Projectmanagement, Qualitymanagement and all things "schauderhaft"


Top
 Profile  
 
 Post subject:
PostPosted: Tue Feb 19, 2008 6:01 am 
Newbie

Joined: Mon Dec 17, 2007 11:50 am
Posts: 14
schauder wrote:
Can you post some code?

Here is what I do in my persistence class. There are two methods: save() and load(), which can be started by the user independently, but not simultaneously.

Code:
private void save()
{
try
{
     this.session = this.sessionFactory.getCurrentSession();
     Transaction tx = this.session.beginTransaction();
     SQLQuery sqlq;   
     sqlq = this.session.createSQLQuery("truncate abstractnodes, circlelocations, connections, edge_node, edgelocations, edges, environmentevents, event_lane, events, lanes, location_edge, locations, nodes, pointofinterests, polygonlocations, polygonpoints, roadevents, tldurations, trafficlight_edge_tlsl, trafficlights, trafficlightstatelistentries, trafficlightstatelists, way_trafficlight, ways;");
         sqlq.executeUpdate();

//[...] Then I set the IDs of all objects to 0.

    for(Edge e: this.edges)
    {
   for(Lane l: e.getLanes())
   {
      session.save(l);
   }
   session.save(e);
         
    }
    for(Way w: this.ways)
    {
   session.save(w);
    }      
    for(Node n: this.nodes)
    {
   if(n instanceof TrafficLight)
   {
      TrafficLight tl = (TrafficLight)n;
      for(Entry<Edge, TrafficLightStateList> entry:  tl.getDefaultLogic().entrySet())
      {
         for(TrafficLightStateListEntry states:  entry.getValue().getStates())
         {
            this.session.save(states);
         }
         this.session.save(entry.getValue());               }
   }
   session.save(n);
    }      
    for(PointOfInterest p: this.pois)
    {
   session.save(p);
    }
    for(Event ev: this.events)
    {
      session.save(ev);
      session.save(ev.getLocation());
    }

    tx.commit();
catch(Exception e)
    {
   e.printStackTrace();
    }


Code:
private void load()
{
     this.session = this.sessionFactory.getCurrentSession();
     Transaction tx = this.session.beginTransaction();
     Query q;
     q = this.session.createQuery("from PointOfInterest");
     List<PointOfInterest> pois = q.list();

     q = this.session.createQuery("from Edge");
     List<Edge> edges = q.list();

     q = this.session.createQuery("from Node");
     List<Node> nodes = q.list();

     q = this.session.createQuery("from Way");
     List<Way> ways = q.list();

     this.setEdges(new ArrayList<Edge>(edges));
     this.setNodes(new ArrayList<Node>(nodes));
     this.setWays(new ArrayList<Way>(ways));
     this.setPointOfInterests(pois);
     
    Query q;
    q = this.session.createQuery("from EnvironmentEvent");
    List<EnvironmentEvent> environmentevents = q.list();
    q = this.session.createQuery("from RoadEvent");
    List<RoadEvent> roadevents = q.list();
    this.setRoadEvents(new ArrayList<RoadEvent>(roadevents));
    this.setEnvironmentEvents(new ArrayList<EnvironmentEvent>(environmentevents));
    tx.commit();
catch(Exception e)
{
     e.printStackTrace();
}


The data classes that cause problems here are:

Code:
@Entity
@Table(name="events")
@Inheritance(strategy=InheritanceType.JOINED)
@SequenceGenerator(name="SEQ_EVENT", sequenceName="events_id_seq")
public abstract class Event extends DeepCloner implements Serializable {
   
   @Id
   @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_EVENT")
   public int id;
   
   private int startTime;
   
   private int endTime;
   
   @OneToOne(fetch=FetchType.EAGER)
   @JoinColumn(name="location")
   @Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE, CascadeType.ALL})
   protected Location location;
[...]


Code:
@Entity
@Table(name="environmentevents")
public class EnvironmentEvent extends Event implements Serializable {
//[...] no additional relationships


Code:
@Entity
@Table(name="roadevents")
public class RoadEvent extends Event implements Serializable {
   
@ManyToMany(fetch=FetchType.EAGER)
   @JoinTable(
           name="event_lane",
           joinColumns={@JoinColumn(name="event")},
           inverseJoinColumns={@JoinColumn(name="lane")}
       )
   @IndexColumn(name = "indexinroadevent", base=0)
   @Cascade({CascadeType.SAVE_UPDATE, CascadeType.PERSIST})
   private List<Lane> blockedLanes = new ArrayList<Lane>();

[...]


Code:
@Entity
@Table(name="locations")
@Inheritance(strategy=InheritanceType.JOINED)
@SequenceGenerator(name="SEQ_LOC", sequenceName="locations_id_seq")
public abstract class Location extends DeepCloner implements Serializable {

   @Id
   @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_LOC")
   public int id;
   
   @ManyToMany(fetch=FetchType.EAGER)
   @JoinTable(
           name="location_edge",
           joinColumns={@JoinColumn(name="location")},
           inverseJoinColumns={@JoinColumn(name="edge")}
       )
   @Cascade({CascadeType.SAVE_UPDATE, CascadeType.PERSIST})
   protected List<Edge> edges;
[...]


Code:
@Entity
@Table(name="edgelocations")
public class EdgeLocation extends Location implements Serializable {
[...]


Code:
@Entity   
@Table(name="circlelocations")
public class CircleLocation extends Location implements Serializable {

@Embedded
   @AttributeOverrides( {
       @AttributeOverride(name="longitude", column = @Column(name="long") ),
       @AttributeOverride(name="latitude", column = @Column(name="lat") ),
       @AttributeOverride(name="altitude", column = @Column(name="alt"))
    } )
   private GlobalPosition center;


Code:
@Entity
@Table(name="polygonlocations")
public class PolygonLocation extends Location {
   
   /**
    *
    */
   private static final long serialVersionUID = -6319440118425086537L;
   @CollectionOfElements(fetch=FetchType.EAGER)
   @JoinTable( name="polygonpoints",
               joinColumns = @JoinColumn(name="polygonlocation")       )   
   @IndexColumn(name = "indexinlocation", base=0)   
   private List<GlobalPosition> points = new ArrayList<GlobalPosition>();


Maybe this helps?


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 20, 2008 1:28 pm 
Expert
Expert

Joined: Thu Jul 05, 2007 9:38 am
Posts: 287
burnt wrote:
I have two subclasses of Location, and it works for one, but not for the other. The only difference regarding relations is, that the one, for that it works, has several Edges, the one, for that it doesn't work, can only have one.


I don't see these to subclasses of location ... Location has a collection of edges which is inherited by the various subclasses?

What I noticed, which looks odd to me is: Events have a ONE-TO-ONE relation to locations, shouldn't that be a Many-to-one?. It simply looks odd, because 1:1 relation are rare.

One little thing to check: in load() check that session.isDirty returns false.

Last idea for today: activate sql logging and pinpoint the statment, that actually does the superfluos insert.

Sorry no real idea what is going on.

_________________
Please rate useful posts.


Schauderhaft: Softwaredevelopment, Projectmanagement, Qualitymanagement and all things "schauderhaft"


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 9 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.