2

the full error line from my example is "[PersistenceException: org.h2.jdbc.JdbcSQLException: Parameter "#1" is not set; SQL statement: delete from class4 where (class3_id) in (?) [90012-158]]"

this was occurring in my unit tests, so decided to create a test project to try and reproduce it and it did.

basically I have classes 1-4 each one related with a onetomany i attempt to create them and then delete them in the order 1,2,3,4 4,3,2,1 but I get this error.

the classes are all the same apart from the numbers (and the last class not having a list

@Entity
public class Class1 extends Model{

/**
 * 
 */
private static final long serialVersionUID = 4322329984247299024L;

@Id
@GeneratedValue
public Long id;



@OneToMany(mappedBy="class1",cascade={CascadeType.PERSIST, CascadeType.ALL})
private List<Class2> class2s = new ArrayList<Class2>();

public Class2 add()
{
    Class2 class2 = new Class2(this);
    Class2.create(class2);
    return class2;
}


@play.db.ebean.Transactional 
public static void create(Class1 class1) {
    class1.save();
    }



  @play.db.ebean.Transactional 
 public static void delete(Class1 class1) {
      class1.delete();
    }
}

and my application code which causes the error runs as follows

      Class1 class1 = new Class1();
  Class1.create(class1);
  Class2 class2 = class1.add();
  class1.add();

  Class2.delete(class2);
  Class1.delete(class1);

I have also attached a sample application showing it happening, I would be most greatful if someone could point out what I have done wrong, or if it is a bug with the API if anyone knows how I could work around it.

http://stowelly.co.uk/play-2.0.3-persistence-test.zip

thank you

Stowelly
  • 1,260
  • 2
  • 12
  • 31

2 Answers2

2

Seems this is a bug in Ebean

http://www.avaje.org/bugdetail-420.html

anyway, a temporary workaround while this is beign addressed is the following code in each of the classes delete functions

 @play.db.ebean.Transactional 
     public static void delete(Class2 class2)
  {  
     List<Class3> list = class2.getClass3s();
     for(int i = 0; i < list.size(); ++i)
     {
       Class3.delete(list.get(i));
     }  
     list.clear();
     class2.getClass1().getClass2s().remove(class2);
     class2.delete();
    }
Stowelly
  • 1,260
  • 2
  • 12
  • 31
1

Don't use stuff like @Transactional in your entity. Instead use this on business logic/persistence.

@Entity
public class A
{
    Long id;
    List<B> bs;

    //...
}

public class DAO
{
    @Transactional
    public void addBtoA(A a, B b)
    {
         b = em.persist(b);
         a = em.find(a);
         a.addB(b);
         em.persist(a);
    }
}

The simple explanation is that a transaction is there so it can rollback if something goes wrong. This is to prevent half persisted stuff, in the example B being commited, A not existing, B being a non referenced entry in the DB.

siebz0r
  • 18,867
  • 14
  • 64
  • 107