0

I'm quite confused, I'm trying to find out why I'm getting the creation of two Customers in the database with the following code with no luck. I tried to cut all the noise from the code, I hope I didn't erased anything important for the resolution of the problem. Here are in the following order : Entities, DAOs, Services and the SpecialService with the specialTreatment which holds the bogus behavior.

In the specialTreatment the aim is to get an existing Order with no Customer linked to it, create a new Customer, and associate it to the order.

Entities :

Order.java :

@Entity
public class Order {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "pk_id_order")
    private Integer id;

    // Other fields ...

    @BatchFetch(value = BatchFetchType.IN)
    @JoinColumn(name = "fk_id_customer", referencedColumnName = "pk_id_customer")
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    private Customer customer;

    // Other fields ...

    // Getter & setters for each field

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 79 * hash + (this.id != null ? this.id.hashCode() : 0);

        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null || !(obj instanceof Order)) {
            return false;
        }

        final Order other = (Order) obj;
        if (this.id != other.id && (this.id == null || !this.id.equals(other.id))) {
            return false;
        }

        return true;
    }
}

Customer.java :

@Entity
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "pk_id_customer")
    private Integer id;

    // Other fields

    @OrderBy(value = "createdAt DESC")
    @OneToMany(mappedBy = "customer", fetch = FetchType.LAZY)
    private List<Order> orders;

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

    @Override
    public boolean equals(Object object) {
        if (object == null || !(object instanceof Customer)) {
            return false;
        }

        final Customer other = (Customer) object;
        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
            return false;
        }

        return true;
    }
}

DAOs :

@Repository
@Transactional
public class CustomerDao {

    @PersistenceContext
    protected EntityManager em;

    public void create(Customer customer) {
        this.em.persist(customer);
    }
}

@Repository
@Transactional
public class OrderDao {

    @PersistenceContext
    protected EntityManager em;

    public Order edit(Order order) {
        return this.em.merge(order);
    }
}

Services :

@Service
@Transactional
public class CustomerService {

    @Autowired
    private CustomerDao customerDao;

    public void create(Customer customer) {
        this.customerDao.create(customer);
    }
}

@Service
@Transactional
public class OrderService {

    @Autowired
    private OrderDao orderDao;

    public void edit(Order order) {
        this.orderDao.edit(order);
    }
}

@Service
@Transactional
public class SpecialService {

    @Autowired
    private CustomerService customerService;

    @Autowired
    private OrderService orderService;

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void specialTreatment(Order order) {
        Customer customer = new Customer();
        // Fill customer ...

        this.customerService.create(customer); // LINE X

        order.setCustomer(customer); // LINE Y

        this.orderService.edit(order);
    }
}

Note : When commenting line X : - There is no customer created (as expected), the order is edited as expected When commenting line Y : - The customer is created as expected (only one row) but it is not linked to my Order

The code is called from a Spring MVC controller

Any advice ?

Alexandre Jacob
  • 2,993
  • 3
  • 26
  • 36
  • Have you implemented proper equals/hashcode implementation in the entities?! Next there is no cascade in your `Order` entity and is it a bidirectional or unidirectional relationship? – M. Deinum Oct 14 '13 at 09:48
  • Just edited my question with equals/hashcode of Customer and Order (generated by Netbeans). They are based on the auto incremented ID which is not set for Customer at this point. I also added a relation from Customer to Order which I'm not using here – Alexandre Jacob Oct 14 '13 at 10:01
  • You should always set both sides of the relationship (in my experience Hibernate can loose track if you don't). – M. Deinum Oct 14 '13 at 11:14
  • I tried to add the order to the list of orders in the customer before persisting anything but the same problem occurs. I'm really confused ! – Alexandre Jacob Oct 14 '13 at 20:52
  • Could it be serializing the objects to the CustomerService and OrderService? If so, it will appear as if the customer instance you call persist on is different than the one associated to the Order. Try calling em.flush() in the CustomerService create method to have the primary key assigned, and check that the value was set after the create call in specialTreatment. – Chris Oct 15 '13 at 14:17
  • @Chris : I tried but it's still creating two rows. I tried to add **@Transactional(propagation = Propagation.REQUIRES_NEW)** to *customerService.create* and it fixed the problem, but I'd like to keep everything in a single transaction. – Alexandre Jacob Oct 15 '13 at 16:08
  • If you call em.flush in the create call, is the id value set in the customer after the customerService.create call? if it is not set, then you will need pass back the customer and use that instance in the order.setCustomer call. – Chris Oct 15 '13 at 19:02
  • I just did the check, the ID is set in the *create* method just after the *flush*, it's also set in the *specialTreatment* method after the *create* call – Alexandre Jacob Oct 16 '13 at 08:15

0 Answers0