2

UPDATE 2014-01-29: I have changed relationshis so entity code and error changed too

I have to store some data in a database and my relations are like this: Order3d 1-----* Draw 1-----* Line I want to save everything like this:

Order3d o=new Order3d();
//add data to order (lines and draws)
Session s=HibernateUtils.getSessionFactory().openSession();
s.save(o);
s.close();

I don't have runtime error but now my line is not inserted (only order3d and drawfile are saved)

here are my entities (obviously, they are POJO so I didn't copy getters and setters):

@Entity
@Table (name="order3d")
public class Order3d implements Serializable {
    private static final long serialVersionUID = -2241346447352903470L;
    public enum State {DEMAND, ESTIMATED, PAYED, PENDING, PRODUCED, SENT, DELIVERED};
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column (name="id")
    private int id;
    @Column (name="person")
    private int person;
    @Column (name="state", columnDefinition="smallint")
    private State state;
    @Column (name="labor_expense")
    private float laborExpense=0;
    @Column (name="travel_expense")
    private float travelExpense=0;
    @Column (name="validity_date")
    private Date validityDate;
    @Column (name="demand_date")
    private Date demandDate;
    @Column (name="estimate_date")
    private Date estimateDate;
    @Column (name="order_date")
    private Date orderDate=null;
    @Column (name="modification", columnDefinition="TEXT")
    private String modification;
    @Column (name="delivery", columnDefinition = "BIT", length = 1)
    private Boolean delivery=true;
    @OneToMany(mappedBy="order3d", cascade=CascadeType.ALL)
    private Set<DrawFile> myDraws=new HashSet<DrawFile>(5);
    public void addDrawFile(DrawFile df) {
        df.setOrder3d(this);
        myDraws.add(df);
    }
}
@Entity
@Table (name="draw")
public class DrawFile implements Serializable {
    private static final long serialVersionUID = -9024754876558087847L;
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column (name="id")
    private int id;
    @Column (name="hashname", columnDefinition="CHAR(64)")
    private String hashname;
    @Column (name="filename")
    private String filename="";
    @Column (name="accepted", columnDefinition = "BIT", length = 1)
    private Boolean accepted=true;
    @Column (name="format")
    private String format;
    @Column (name="size")
    private int size;
    @Column(name="width")
    short width;
    @Column(name="depth")
    short depth;
    @Column(name="height")
    short height;
    @OneToMany(mappedBy="draw", cascade=CascadeType.ALL)
    private Set<Order3dLine> myLines=new HashSet<Order3dLine>(5);
    @ManyToOne
    @JoinColumn(name="order3d_id")
    private Order3d order3d;
    public void addLine(Order3dLine l) {
        l.setDraw(this);
        myLines.add(l);
    }
}
@Entity
@Table (name="line3d")
public class Order3dLine implements Serializable {
    private static final long serialVersionUID = 3993578603382571145L;
    @NaturalId
    @ManyToOne
    @JoinColumn(name="draw_id")
    private DrawFile draw;
    @Column (name="quantity")
    private short quantity=0;
    @Id
    @Column (name="material")
    private String material;
    @Id
    @Column (name="color")
    private int color;
    @Column(name="produced")
    short produced=0;
    @Column(name="duration")
    short duration=0;
}

Here are my MySQL tables:

CREATE TABLE `draw` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `filename` varchar(255) DEFAULT NULL,
  `format` varchar(6) DEFAULT NULL,
  `hashname` char(64) DEFAULT NULL,
  `accepted` bit(1) NOT NULL DEFAULT b'0',
  `size` int(11) NOT NULL DEFAULT '0',
  `order3d_id` int(11) NOT NULL,
  `width` smallint(6) NOT NULL DEFAULT '0',
  `depth` smallint(6) NOT NULL DEFAULT '0',
  `height` smallint(6) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  CONSTRAINT `fk_draw_order3d` FOREIGN KEY (`id`) REFERENCES `order3d` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf-8;
/*!40101 SET character_set_client = @saved_cs_client */;

CREATE TABLE `line3d` (
  `draw_id` int(11) NOT NULL,
  `material` varchar(10) NOT NULL,
  `color` int(11) NOT NULL,
  `quantity` smallint(6) NOT NULL DEFAULT '0',
  `produced` smallint(6) NOT NULL DEFAULT '0',
  `duration` smallint(6) NOT NULL DEFAULT '0',
  `layers` tinyint(1) NOT NULL DEFAULT '1',
  PRIMARY KEY (`draw_id`,`material`,`color`),
  CONSTRAINT `fk_line_draw` FOREIGN KEY (`draw_id`) REFERENCES `draw` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf-8;

CREATE TABLE `order3d` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `person` int(11) DEFAULT NULL,
  `state` smallint(6) DEFAULT NULL,
  `labor_expense` float DEFAULT NULL,
  `travel_expense` float DEFAULT NULL,
  `validity_date` date DEFAULT NULL,
  `estimate_date` date DEFAULT NULL,
  `order_date` date DEFAULT NULL,
  `delivery` bit(1) NOT NULL DEFAULT b'0',
  `modification` text,
  `demand_date` date DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `fk_order_user` (`person`),
  CONSTRAINT `fk_order_user` FOREIGN KEY (`person`) REFERENCES `person` (`id`) ON DELETE SET NULL ON UPDATE SET NULL
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf-8;
Athanor
  • 855
  • 1
  • 16
  • 34
  • Looks like your 'DrawLine' object is not persisted before saving your 'ObjectLine' object. Try adding 'cascade=CascadeType.ALL' to your 'DrawLine draw' in 'OrderLine' class. – Sudarshan_SMD Jan 28 '14 at 10:30
  • `@Id @OneToOne(fetch = FetchType.LAZY, cascade=CascadeType.ALL) @JoinColumn(name="draw") @Embedded private DrawFile draw;` I still get the same error – Athanor Jan 28 '14 at 11:37

1 Answers1

0

(1) You have a bi-directional relation between order and order line. Hibernate expects you to assign order to line like in this convenience method:

@Entity
@Table(name="ORDERS")       
public class Order {
    [...]

    public void addLine(OrderLine line) {
        line.setOrder(this);
        myLines.add(line);
    }

}

See also this thread.

(2) "order" is not accepted as an valid table table name. Choose for example "orders".

(3) You forgot the cascade option on your one-to-one relation between order line and draw. Consider using @Embedded instead of @OneToOne. See Hibernate Doc

I put together minimal working example:

Order:

@Entity
@Table(name = "ORDERS")
public class Order {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column (name = "id")
    private Long id;

    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name="line_id", nullable = false)
    private Set<OrderLine> lines = new HashSet<OrderLine>();

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Set<OrderLine> getLines() {
        return lines;
    }

    public void setLines(Set<OrderLine> lines) {
        this.lines = lines;
    }

    public void addLine(OrderLine line) {
        line.setOrder(this);
        lines.add(line);
    }
}

Order line:

@Entity
@Table(name = "ORDER_LINES")
public class OrderLine {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column (name = "id")
    private Long id;

    @ManyToOne(fetch = FetchType.EAGER)
    private Order order;

    @Column(name = "content")
    private String content;

    @Embedded
    private OrderDraw draw;

    public OrderDraw getDraw() {
        return draw;
    }

    public void setDraw(OrderDraw draw) {
        this.draw = draw;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Order getOrder() {
        return order;
    }

    public void setOrder(Order order) {
        this.order = order;
    }
}

Order Draw (whatever this is)

@Embeddable
public class OrderDraw {
    private int width;
    private int height;

    public OrderDraw() {
        this(0,0);
    }

    public OrderDraw(int width, int height) {
        this.width = width;
        this.height = height;
    }

    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }
}
Community
  • 1
  • 1
Lars Behnke
  • 1,901
  • 2
  • 14
  • 14
  • I added your code and replaced `new Order().getMyLines().add(sometline) ;` by `new Order().addLine(someline);` and I got the same error :( – Athanor Jan 28 '14 at 11:40
  • Please add thesesettings to your hibernate configuration and append the log output to your question: hibernate.show_sql=true hibernate.format_sql=true – Lars Behnke Jan 28 '14 at 11:57
  • `Hibernate: insert into order (delivery, demand_date, estimate_date, labor_expense, modification, order_date, person, state, travel_expense, validity_date) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) Hibernate: select orderlin_.order, orderlin_.material, orderlin_.draw, orderlin_.color, orderlin_.depth as depth3_2_, orderlin_.duration as duration4_2_, orderlin_.height as height5_2_, orderlin_.produced as produced6_2_, orderlin_.quantity as quantity7_2_, orderlin_.width as width8_2_ from line orderlin_ where orderlin_.order=? and orderlin_.material=? and orderlin_.draw=? and orderlin_.color=? ` – Athanor Jan 28 '14 at 12:13
  • I dont't know which DB you are using , but I suspect there is another glitch in the code: "order" is not an valid table name. I put together a working example for you. See updated answer. – Lars Behnke Jan 28 '14 at 13:29
  • My real table name is not order but Order3d (I thought it was simplier like this). I added my table create instructions. I dont understand how the mapping works with your code (I'm also a hibernate beginner) without column names. Do I need to change order3d in OrderLine table with suffix _id? (order3d -> order3d_id) – Athanor Jan 28 '14 at 14:14
  • If there is no @Column annotation Hibernate just uses the property name as column name. It is best practice to append "_id" or "_fk" to foreign key column names. It is not mandadory, though. BTW, you should use @GeneratedValue(strategy=GenerationType.AUTO) - otherwise there is chance that you DB does not support the strategy IDENTITY. – Lars Behnke Jan 29 '14 at 08:22
  • Thanks Lars Behnke for the information. I have made changes so I have two OneToMany in a row. My lines are not inserted... again :'( – Athanor Jan 29 '14 at 10:34
  • Hmm... I am running out of ideas. I've tested my code successfully in a unit test using the H2 DB. Are you using MySQL's MyISAM engine. If so try using InnoDB, since MyISAM cannot handle foreign key constraints. Try making progress step by step. First focus on Order and OrderLine and ignore everything else. If persisting this parent/child entity combination works, add your draw entities. – Lars Behnke Jan 30 '14 at 09:56
  • I'm using InnoDB. I currently solve the problem by saving the order and then the lines even if it is not a good practice. Thanks for your help. – Athanor Jan 30 '14 at 14:30