Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [eclipselink-users] (Long) Oddities using EclipseLink 2, NetBeans 6.8, EJB and GlassFish 3.0

Hello Roger,

There seem to be a few test case problems that might be confusing the situation: Dupclient never gets its first name set - you are calling client.setFirstName("Roger"); then a bit later calling client.setFirstName("Fred");

So the client that gets written should have a name of Fred.  The dupClient never gets a name set, and so will be null.  You also call
mobile.setClient(dupclient); and do not set the DupMobile client at all. Since

As for the rollback you are setting, you are calling,
context.setRollbackOnly
but this seems to be a sessionContext, not the persistence context or the transaction so I'm not sure that this will cause the transaction to rollback.
Best Regards,
Chris


Roger wrote:
On Wednesday 06 January 2010 16:23:43 James Sutherland wrote:
I'm not sure what you intend to happen, also perhaps include an SQL trace.

Hi James

Thanks for taking the time to look at this for me. I'd love to have an SQL trace to see what's going on but when using the glassfish embedded container, it appears to be ignoring the logging properties in persistence.xml. I've tried both
<property name="eclipselink.logging.level" value="FINE"/> and
<property name="javax.persistence.logging.level="FINE"/>

I've also tried putting both these values into a map and used, for example;

Map<String,String> properties = new HashMap<String, String>();
properties.put("eclipselink.logging.level","FINE");
EJBContainer ejbc = EJBContainer.createEJBContainer(properties);

and I still get no  SQL trace.

You test code looks a little odd.  The main issue with it is that the
 client Id is a generated Id and never passed back to the test client, so
 will remain null.  This will trigger your delete to first merge a new
 client, then try to delete this new client.


That bit seems to work. In the second test I see "client" get inserted into the database. "dupclient" never gets persisted. When I call the delete(client) I see "client" disappear from the database, but "dupclient" appears albeit with the firstName=null. I expected neither to be in the database when I'd finished.

Regards

RogerV wrote:
Hi

This is my first foray into the field of EJB and JPA persistence using
EclipseLink 2.0. Given my knowledge of these areas I've no idea where the
problem lies and I hope that someone can point me in the right direction.

I've created enities, CLient and Phone (an abstract class) with  a bi-
directional @ManyToOne between them, and MobilePhone as a concrete entity
class. I've used the NetBeans code generation tool to create the
ClientFacade
and PhoneFacade stateless session beans that actually perform the CRUD
operation. I've then created a ClientService  stateless session bean that
will
contain the business logic that controls the CRUD operations. Lastly, I
have
my ClientServiceTest class that contains my unit tests.


package com.vasilikon.processes;

import com.vasilikon.entity.Client;
import com.vasilikon.entity.Example;
import com.vasilikon.entity.MobilePhone;
import com.vasilikon.exceptions.PhoneNumberException;
import javax.ejb.SessionContext;
import javax.ejb.embeddable.EJBContainer;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;

/**
 *
 * @author varleyr
 */
public class ClientServiceTest {

    static EJBContainer ejbc;


    public ClientServiceTest() {
    }



    @BeforeClass
    public static void setUpClass() throws Exception {
    ejbc = EJBContainer.createEJBContainer();

    }

    @AfterClass
    public static void tearDownClass() throws Exception {
    ejbc.close();
    }

    @Before
    public void setUp() {
    }

    @After
    public void tearDown() {
    }

    /**
     * Test of create method, of class ExampleService.
     */
    @Test
    public void testCreate() throws Exception {
        System.out.println("create");

        Client client = new Client();
        client.setFirstName("Roger");

        MobilePhone mobile = new MobilePhone(99887766);
        mobile.setClient(client);

        client.getPhones().add(mobile);

        ClientService instance = (ClientService)
ejbc.getContext().lookup("java:global/classes/ClientService");
        instance.create(client);
        assertTrue(client.getId() != null);
        instance.delete(client);
    }

    @Test
    public void testCreateDuplicatePhoneNumber() throws Exception {
        System.out.println("create");

        Client client = new Client();
        client.setFirstName("Roger");

        MobilePhone mobile = new MobilePhone(99887766);
        mobile.setClient(client);

        client.getPhones().add(mobile);

        ClientService instance = (ClientService)
ejbc.getContext().lookup("java:global/classes/ClientService");
        instance.create(client);
        assertTrue(client.getId() != null);

        Client dupclient = new Client();
        client.setFirstName("Fred");

        MobilePhone dupmobile = new MobilePhone(99887766);
        mobile.setClient(dupclient);

        dupclient.getPhones().add(dupmobile);

        try {
            instance.create(dupclient);
            fail();
        }
        catch (PhoneNumberException e) {
        }
        finally {
            instance.delete(client);
        }

    }

}


The first test in the class simply tests for entity creation, and works
as expected and the client and phone entities are created with an client
id of 1
and are removed at the end of the test as expected.

However, the second test testCreateDuplicatePhoneNumber() behaves oddly.
Stepping through under debug I see the first entity created and appearing
in
the database as expected with an assigned id of "2".  I also see the
entry on
the phone table associated with customer id 2.  I see the second entity
class
populated correctly with the duplicate phone number and firstName of
Fred. The
code correctly detects the duplicated phone number, does not persist the
Client and then deletes the original client from the database. Now when I
physically check the database, the Client table contains a row with an id
= 3
and FirstName = null and the Phone table contains a fully populated
record associated with Client_ID = 3.

And I have no idea why this is happening. I get the same result whether I
specify the context.setRollbackOnly() or not. I'm guessing that because I
see
the row in the client table with a firstName value of null when I know
that
the entity instance was initialized to the value "Fred", somehow the
Phone entity is being persisted and auto generating the back reference to
the Client

Any pointers would be welcome. Source code is below

Regards

package com.vasilikon.entity;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;

/**
 *
 * @author varleyr
 */
@Entity
public class Client implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String firstName;

    @OneToMany(mappedBy = "client", cascade=CascadeType.ALL)
    private List<Phone> phones;

    public Client() {
        this.phones = new ArrayList();
    }


    public Long getId() {
        return id;
    }

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

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public List<Phone> getPhones() {
        return phones;
    }

    public void setPhones(List<Phone> phones) {
        this.phones = phones;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id
fields
are not set
        if (!(object instanceof Client)) {
            return false;
        }
        Client other = (Client) object;
        if ((this.id == null && other.id != null) || (this.id != null &&
!this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "com.vasilikon.entity.Client[id=" + id + "]";
    }

}

package com.vasilikon.entity;

import java.util.List;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

/**
 *
 * @author varleyr
 */
@Stateless
@LocalBean
public class ClientFacade {
    @PersistenceContext(unitName = "Devere")
    private EntityManager em;

    public void create(Client client) {
        em.persist(client);
    }

    public void edit(Client client) {
        em.merge(client);
    }

    public void remove(Client client) {
        em.remove(em.merge(client));
    }

    public Client find(Object id) {
        return em.find(Client.class, id);
    }

    public List<Client> findAll() {
        CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
        cq.select(cq.from(Client.class));
        return em.createQuery(cq).getResultList();
    }

    public List<Client> findRange(int[] range) {
        CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
        cq.select(cq.from(Client.class));
        Query q = em.createQuery(cq);
        q.setMaxResults(range[1] - range[0]);
        q.setFirstResult(range[0]);
        return q.getResultList();
    }

    public int count() {
        CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
        Root<Client> rt = cq.from(Client.class);
        cq.select(em.getCriteriaBuilder().count(rt));
        Query q = em.createQuery(cq);
        return ((Long) q.getSingleResult()).intValue();
    }

}

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package com.vasilikon.entity;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToOne;

/**
 *
 * @author varleyr
 */
@Entity
public abstract class Phone implements Serializable {

    @Id
    private int number;

    @ManyToOne
    private Client client;
    private static final long serialVersionUID = 1L;



    public Phone() {

    }

    public Phone(int number) {
       this.number = number;
    }

   public int getId() {
       return number;
   }

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

    public Client getClient() {
        return client;
    }

    public void setClient(Client client) {
        this.client = client;
    }


    @Override
    public String toString() {
        return "com.vasilikon.entity.Phone[number=" + number + "]";
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Phone other = (Phone) obj;
        if (this.number != other.number) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 29 * hash + this.number;
        return hash;
    }





}

package com.vasilikon.entity;

import javax.persistence.Entity;

/**
 *
 * @author varleyr
 */
@Entity
public class MobilePhone extends Phone {



    public MobilePhone() {
        super();
    }

    public MobilePhone(int number) {
        super(number);
    }

}

package com.vasilikon.entity;

import java.util.List;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

/**
 *
 * @author varleyr
 */
@Stateless
@LocalBean
public class PhoneFacade {
    @PersistenceContext(unitName = "Devere")
    private EntityManager em;

    public void create(Phone phone) {
        em.persist(phone);
    }

    public void edit(Phone phone) {
        em.merge(phone);
    }

    public void remove(Phone phone) {
        em.remove(em.merge(phone));
    }

    public Phone find(Object id) {
        return em.find(Phone.class, id);
    }

    public List<Phone> findAll() {
        CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
        cq.select(cq.from(Phone.class));
        return em.createQuery(cq).getResultList();
    }

    public List<Phone> findRange(int[] range) {
        CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
        cq.select(cq.from(Phone.class));
        Query q = em.createQuery(cq);
        q.setMaxResults(range[1] - range[0]);
        q.setFirstResult(range[0]);
        return q.getResultList();
    }

    public int count() {
        CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
        Root<Phone> rt = cq.from(Phone.class);
        cq.select(em.getCriteriaBuilder().count(rt));
        Query q = em.createQuery(cq);
        return ((Long) q.getSingleResult()).intValue();
    }

}

package com.vasilikon.processes;

import com.vasilikon.entity.Client;
import com.vasilikon.entity.ClientFacade;
import com.vasilikon.entity.Phone;
import com.vasilikon.entity.PhoneFacade;
import com.vasilikon.exceptions.PhoneNumberException;
import javax.annotation.Resource;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.ejb.LocalBean;
import javax.ejb.SessionContext;

/**
 *
 * @author varleyr
 */
@Stateless
@LocalBean
public class ClientService {

    @EJB
    ClientFacade clientFacade;

    @EJB
    PhoneFacade phoneFacade;

    private SessionContext context;

    @Resource
    public void setSessionContext(SessionContext context) {
        this.context = context;
    }

    public void create(Client client) throws PhoneNumberException {

        for (Phone phone : client.getPhones()) {
            Phone exists = phoneFacade.find(phone.getId());

            if (exists != null) {
                 context.setRollbackOnly();
                throw new PhoneNumberException("Phone number " +
phone.getId()
                        + " is already in use");
            }
        }

        clientFacade.create(client);
    }

    public void delete(Client client) {
        clientFacade.remove(client);
    }
}
-----
http://wiki.eclipse.org/User:James.sutherland.oracle.com James Sutherland
http://www.eclipse.org/eclipselink/
 EclipseLink ,  http://www.oracle.com/technology/products/ias/toplink/
TopLink
Wiki:  http://wiki.eclipse.org/EclipseLink EclipseLink ,
http://wiki.oracle.com/page/TopLink TopLink
Forums:  http://forums.oracle.com/forums/forum.jspa?forumID=48 TopLink ,
http://www.nabble.com/EclipseLink-f26430.html EclipseLink
Book:  http://en.wikibooks.org/wiki/Java_Persistence Java Persistence

_______________________________________________
eclipselink-users mailing list
eclipselink-users@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/eclipselink-users


Back to the top