[
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
|
I'm not sure what you intend to happen, also perhaps include an 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.
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
--
View this message in context: http://old.nabble.com/%28Long%29-Oddities-using-EclipseLink-2%2C-NetBeans-6.8%2C-EJB-and-GlassFish-3.0-tp27001987p27026876.html
Sent from the EclipseLink - Users mailing list archive at Nabble.com.