2961 words

New to Product & Having An Issue

#1
2010-12-16 19:42

Greetings ObjectDB Users!


I'm new to the product, and I've setup a simple test after reading the tutorial, and I'm running into some issues with queries, specifically querying by primary key.   I have a domain object class Called Department, which has a member of type DomainId.  DomainId has two member fields:  String accountId and String objectId.  The following code shows these two classes.

package test.Domain;
 
...imports....
 
@Entity
@Access(AccessType.PROPERTY)
@NamedQueries({
    @NamedQuery(name="Department.findAll", query="SELECT d FROM Department AS d"),
    @NamedQuery(name="Department.byName", query="SELECT d from Department AS d WHERE d.name = :name"),
    @NamedQuery(name="Department.findByCmpPK", 
            query="SELECT d FROM test.Domain.Department AS d " +
                    "WHERE d.domainId.accountId = :aid AND d.domainId.objectId = :oid"),
    @NamedQuery(name="Department.findByPK", 
            query="SELECT d FROM Department AS d WHERE d.domainId.equals(:id)")
})
public class Department implements Serializable {
    public static final long serialVersionUID = 1L;
 
    private DomainId domainId;
    private String name;
    private Set<Person> employees;
 
    public Department() {
        super();
    }
 
    public Department(DomainId domainId, String name, Set<Person> employees) {
        super();
        this.domainId = domainId;
        this.name = name;
        this.employees = employees;
    }
 
    @EmbeddedId
    public DomainId getDomainId() {
        return domainId;
    }
 
    public void setDomainId(DomainId domainId) {
        this.domainId = domainId;
    }
 
    @Unique(name="name2")
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    @OneToMany(fetch=FetchType.LAZY)
    public Set<Person> getEmployees() {
        return employees;
    }
 
    public void setEmployees(Set<Person> employees) {
        this.employees = employees;
    }
 
    public boolean equals(Object obj) {
        if(((Department) obj).getDomainId() == null || this.domainId == null)
            return false;
        return this.domainId.equals(obj);
    }
}
package test.Domain;
 
...imports....
 
@Embeddable
@Access(AccessType.PROPERTY)
public class DomainId implements Serializable {
    public static final long serialVersionUID = 1L;
 
    private String accountId;
    private String objectId;
 
    public DomainId(String accountId, String objectId) {
        super();
        this.accountId = accountId;
        this.objectId = objectId;
    }
 
    public DomainId() {
        super();
    }
 
    @Basic(optional=false)
    public String getAccountId() {
        return accountId;
    }
 
    public void setAccountId(String accountId) {
        this.accountId = accountId;
    }
 
    @Basic(optional=false)
    public String getObjectId() {
        return objectId;
    }
 
    public void setObjectId(String objectId) {
        this.objectId = objectId;
    }
 
    public synchronized static String getNewId(){
        UUID uuid = UUID.randomUUID();
        return uuid.toString().replaceAll("-","");  
    }
 
    public boolean equals(Object obj) {
        if(obj instanceof DomainId){
            DomainId foreign = (DomainId) obj;
            if(this.accountId == null || this.objectId == null)
                return false;
            if(foreign.getAccountId() == null || foreign.getObjectId() == null)
                return false;
            return (this.accountId.equals(foreign.getAccountId())) && (this.objectId.equals(foreign.getObjectId()));        
        }
        return false;
    }
}

I then setup a JUnit test case, like this:

package test.test;
 
....imports.....
 
public class TestDepartment {
    private EntityManagerFactory emf = Persistence.createEntityManagerFactory("my-pu");
    private EntityManager em;
    private DomainId departmentId;
    private Department foundResult = null;
 
    @Before
    public void setUp(){
        this.em = emf.createEntityManager();
        this.departmentId = new DomainId(DomainId.getNewId(), DomainId.getNewId());
    }
 
    @Test
    public void createDepartment(){
        Department department = new Department(this.departmentId, "dOne", null);
        try{
            em.getTransaction().begin();
            em.persist(department);
            em.getTransaction().commit();
        }catch(Exception e){
            e.printStackTrace();
            if(em.getTransaction().isActive())
                em.getTransaction().rollback();
            assertTrue(false);
        }
    }
 
    @Test
    public void findDepartment(){
        Department d = em.find(Department.class, this.departmentId);
        assertNotNull(d);
        assertNotNull(d.getDomainId());
        assertEquals(this.departmentId, d.getDomainId());
    }
 
    @Test
    public void queryDepById(){
        TypedQuery<department> q = em.createNamedQuery("Department.findByPK", Department.class);
        q.setParameter("id", this.departmentId);
        Department d = q.getSingleResult();
        assertNotNull(d);
        assertNotNull(d.getDomainId());
        assertEquals(this.departmentId, d.getDomainId());
        this.foundResult = d;
    }
 
    @Test
    public void queryDepByIdComponents(){
        TypedQuery&lr;Department> q = em.createNamedQuery("Department.findByCmpPK", Department.class);
        q.setParameter("aid", this.departmentId.getAccountId());
        q.setParameter("oid", this.departmentId.getObjectId());
        Department d = q.getSingleResult();
        assertNotNull(d);
        assertNotNull(d.getDomainId());
        assertEquals(this.departmentId, d.getDomainId());
        this.foundResult = d;
    }
 
    @Test
    public void simpleCleanUp(){
        assertNotNull(this.foundResult);
        try{
            em.getTransaction().begin();
            em.remove(this.foundResult);
            em.getTransaction().commit();
        }catch(Exception e){
            e.printStackTrace();
            if(em.getTransaction().isActive())
                em.getTransaction().rollback();
            assertTrue(false);
        }
    }
 
    @After
    public void tearDown(){
        //Ensure cleanup happens if lookups fail.
        TypedQuery<Department> q = em.createNamedQuery("Department.findAll", Department.class);
        q.setMaxResults(1000);
        List<Department> departments;
        try{
            do{
                departments = q.getResultList();
                em.getTransaction().begin();
                for(Department d : departments)
                    em.remove(d);
                em.getTransaction().commit();
            }while(departments.size() > 0);
        }catch(Exception e){
            e.printStackTrace();
            if(em.getTransaction().isActive())
                em.getTransaction().rollback();
        }
        //Finish clean up.
        this.foundResult = null;
        this.departmentId = null;
        em.close();
        this.em = null;
        this.emf = null;
    }
}

The first test, createDepartment() succeeds, and I can view the Department object in the database with the ObjectDB Explorer, including it's embedded DomainId which is filled out with the random UUID strings I generated. However, the second test findDepartment fails to find any results and returns NULL, but does not throw any exception. The third and fourth tests fail, and throw the following exception:

[ObjectDB 2.0.3] Query:  SELECT d FROM Department AS d WHERE d. ==> domainId <== .equals(:id)
javax.persistence.PersistenceException
Field 'domainId' is not found in type 'test.Domain.Department' (error 761)
 (position 38)  at com.objectdb.jpa.JpaQuery.getSingleResult(JpaQuery.java:592)
    at test.test.TestDepartment.queryDepById(TestDepartment.java:58)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:616)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:73)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:46)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:180)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:41)
    at org.junit.runners.ParentRunner$1.evaluate(ParentRunner.java:173)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:220)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

This causes the final test, simpleCleanUp to fail because the Department instance is not found, and therefore the privately scoped foundDepartment remains null. Am I doing something wrong with the use of @Embedded, @EmbeddedId or with my JPQL queries or is this a bug? Any help would be greatly appreciated.

john_anderson_ii
john_anderson_ii's picture
Joined on 2010-12-16
User Post #1
#2
2010-12-16 20:02

Hi,

I think that find returns null because different departmentId values are used in persist and find. Notice that setUp is invoked on every test run, generating new departmentId.

I am looking now at the JPQL query issues, which might indicate an ObjectDB bug.

ObjectDB Support
ObjectDB - Fast Object Database for Java (JPA/JDO)
support
support's picture
Joined on 2010-05-03
User Post #87
#3
2010-12-16 21:24

You were absolutely correct about the @Before and @After annotations.  I haven't used JUnit in quite a while and forgot how those worked.  I fixed the test case to use @BeforeClass and @AfterClass and made the changes necessary so the setUp() and tearDown() methods could be static, The em.find() functionality worked as expected.  The query tests still failed however.

john_anderson_ii
john_anderson_ii's picture
Joined on 2010-12-16
User Post #2
#4
2010-12-17 01:55

I think I found and fixed the bug. Thank you for your bug report.

Please try the new build (2.0.3_01).

ObjectDB Support
ObjectDB - Fast Object Database for Java (JPA/JDO)
support
support's picture
Joined on 2010-05-03
User Post #88
#5
2010-12-17 02:09

There is some definite improvement.  The test queryDepByIdComponents() which invokes the named query "SELECT d FROM test.Domain.Department AS d WHERE d.domainId.accountId = :aid AND d.domainId.objectId = :oid") now succeeds.

However, the test queryDepById() which invokes the named query "SELECT d FROM Department AS d WHERE d.domainId.equals(:id)" does not not succeed.  When I use em.find() as pass in the generated DomainId object, the Department object is found.  I also added an assert to the queryDepById() test to ensure that the equals() method of DomainId, which I overrode does work, so my new test and the resulting error follows.

@Test
public void queryDepById(){
            //Ensures DomainId.equals() performs as expected.
    assertTrue(TestDepartment.departmentId.equals(TestDepartment.departmentId));
    TypedQuery<Department> q =
        em.createNamedQuery("Department.findByPK", Department.class);
    q.setParameter("id", TestDepartment.departmentId);
    Department d = q.getSingleResult();
    assertNotNull(d);
    assertNotNull(d.getDomainId());
    assertEquals(TestDepartment.departmentId, d.getDomainId());
    TestDepartment.foundResult = d;
}
[ObjectDB 2.0.3_01] javax.persistence.NoResultException
No matching results for a unique query (error 782)
    at com.objectdb.jpa.JpaQuery.getSingleResult(JpaQuery.java:592)
    at test.test.TestDepartment.queryDepById(TestDepartment.java:61)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:616)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:73)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:46)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:180)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:41)
    at org.junit.runners.ParentRunner$1.evaluate(ParentRunner.java:173)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:220)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

 

john_anderson_ii
john_anderson_ii's picture
Joined on 2010-12-16
User Post #3
#6
2010-12-17 03:43

Please use = instead of equals:

SELECT d FROM Department AS d WHERE d.domainId = :id
ObjectDB Support
ObjectDB - Fast Object Database for Java (JPA/JDO)
support
support's picture
Joined on 2010-05-03
User Post #89
#7
2010-12-17 03:57

Outstanding, that seems to be working.  I think I had the following part of the manual confused.

Instances of user defined classes (entity classes and embeddable classes) can be compared by using the equality operators (=, <>, ==, !=). Note that comparison for these classes follow the logic of == in Java rather than of equals.

john_anderson_ii
john_anderson_ii's picture
Joined on 2010-12-16
User Post #4
#8
2010-12-17 04:09

You are right. The documentation was wrong (about comparison of embedded objects) - I just fixed it.

By the way, equals should also work - at least in embedded mode. I guess you are using client-server mode, and then your equals method is not available on the server. But if you add your DomainId class to the server classpath it should work. Anyway, = is more efficient than equals, and equals is not JPA portable.

ObjectDB Support
ObjectDB - Fast Object Database for Java (JPA/JDO)
support
support's picture
Joined on 2010-05-03
User Post #90
#9
2010-12-17 05:33

I just read your changes to that part of the documentation and it's much more clear on how comparisons should be made.  Thanks for updating it!

john_anderson_ii
john_anderson_ii's picture
Joined on 2010-12-16
User Post #5
#10
2010-12-17 06:42

Thank you for your help in improving ObjectDB.

ObjectDB Support
ObjectDB - Fast Object Database for Java (JPA/JDO)
support
support's picture
Joined on 2010-05-03
User Post #91

Post Reply

Please read carefully the posting instructions - before posting to the ObjectDB website.

  • You may have to disable pop up blocking in order to use the toolbar (e.g. in Chrome).
  • Use ctrl + right click to open the browser context menu in the editing area (e.g. for using a browser spell checker).
  • To insert formatted lines (e.g. Java code, stack trace) - select a style in the toolbar and then insert the text in the new created block.
  • Avoid overflow of published source code examples by breaking long lines.
  • You may mark in paragraph code words (e.g. class names) with the code style (can be applied by ctrl + D).
  • Long stack traces (> 50 lines) and complex source examples (> 100 lines) should be posted as attachments.
Attachments:
Maximum file size: 32 MB
Cancel