Bug 363 : Unique index or primary key violation: ... when saving collection
Priority 
High
Reported Version 
 
Logged By 
Rob
Status 
Fixed
Fixed Version 
2.7.3
Assigned To 
 
Product 
Ebean - core
Duplicate Of 
 
Created 
22/03/2011
Updated 
22/03/2011
Type 
Bug
 
Attachments 
No attachments

Hi

I believe I'm hitting the following issue.

I have X1 and X2 that are new objects. They both rely on Y. The
entities are set to "cascade persist".

When i do this, it fails with a primary key violation, presumably
because Y is already persisted. (pseudo code)

X1.setY(Y);
X2.setY(Y);
List a = new List().add(X1).add(X2);
ebeanServer.save(a); //primary key violation on Y.

When i explicitly insert a transaction in there, and set the mode to
batch, the primary key violation disappears.
Could ebean be changed so that an implicit transaction is opened on
save(collection) ?

The problem really is that ebean is trying to do a insert on the
second Y, when really Y now does exist in the DB store.


Or am i missing something?
Chris

Works:
==========
final User u = new User();
u.setEmailAddress("[email protected]");
u.setName("Mr Test");
u.setPassword("password");

final List bookmarks = new ArrayList();
final Bookmark b1 = new Bookmark();
b1.setBookmarkReference("Acts 2:7-20");
b1.setUser(u);

final Bookmark b2 = new Bookmark();
b2.setBookmarkReference("Acts 7:1-20");
b2.setUser(u);

bookmarks.add(b1);
bookmarks.add(b2);

final Transaction tx = this.ebean.beginTransaction();
tx.setBatchMode(true);
this.ebean.save(bookmarks);
tx.commit();
this.ebean.endTransaction();

Doesn't work:

final User u = new User();
u.setEmailAddress("[email protected]");
u.setName("Mr Test");
u.setPassword("password");

final List bookmarks = new ArrayList();
final Bookmark b1 = new Bookmark();
b1.setBookmarkReference("Acts 2:7-20");
b1.setUser(u);

final Bookmark b2 = new Bookmark();
b2.setBookmarkReference("Acts 7:1-20");
b2.setUser(u);

bookmarks.add(b1);
bookmarks.add(b2);

this.ebean.save(bookmarks);


======
user

package com.tyndalehouse.step.core.data.entities;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

/**
* represents a user entity. A user contains a username and password.
*
* @author Chris
*
*/
@Entity
public class User {
@Id
@GeneratedValue
private Integer id;

@Column
private String name;

@Column
private String password;

@Column
private String emailAddress;

@Column
private String country;

/**
* @return the id
*/
public Integer getId() {
return this.id;
}

/**
* @param id the id to set
*/
public void setId(final Integer id) {
this.id = id;
}

/**
* @return the password
*/
public String getPassword() {
return this.password;
}

/**
* @param password the password to set
*/
public void setPassword(final String password) {
this.password = password;
}

/**
* @return the name
*/
public String getName() {
return this.name;
}

/**
* @param name the name to set
*/
public void setName(final String name) {
this.name = name;
}

/**
* @return the emailAddress
*/
public String getEmailAddress() {
return this.emailAddress;
}

/**
* @param emailAddress the emailAddress to set
*/
public void setEmailAddress(final String emailAddress) {
this.emailAddress = emailAddress;
}

/**
* @return the country
*/
public String getCountry() {
return this.country;
}

/**
* @param country the country to set
*/
public void setCountry(final String country) {
this.country = country;
}
}


=====

package com.tyndalehouse.step.core.data.entities;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;

/**
* A user may have multiple bookmarks
*
* @author Chris
*
*/
@Entity
public class Bookmark {
@Id
@GeneratedValue
private Integer id;

@Column
private String bookmarkReference;

@ManyToOne(cascade = CascadeType.PERSIST)
@Column
private User user;

/**
* @return the id
*/
public Integer getId() {
return this.id;
}

/**
* @param id the id to set
*/
public void setId(final Integer id) {
this.id = id;
}

/**
* @return the bookmarkReference
*/
public String getBookmarkReference() {
return this.bookmarkReference;
}

/**
* @param bookmarkReference the bookmarkReference to set
*/
public void setBookmarkReference(final String bookmarkReference) {
this.bookmarkReference = bookmarkReference;
}

/**
* @return the user
*/
public User getUser() {
return this.user;
}

/**
* @param user the user to set
*/
public void setUser(final User user) {
this.user = user;
}
}

 
Rob 22 Mar 12:33
Reproduced:

I was able to reproduce this. To reproduce you must use subclassing (not enhanced beans) and the issue is that the User has no version property (so Ebean tries to insert the User twice).

Rob 22 Mar 12:37
Fixed in HEAD

fixed in HEAD.

woResponse

Upload a file