0

I currently have a structure as follows (pseudocode):

public class Order
{
    @OneToMany(targetEntity = Orderline.class, fetch = FetchType.LAZY)
    private List<Orderline> orderlines;

    private Client client;
}

public class Orderline
{
    @ManyToOne(mappedBy = 'orderlines')
    private Order order;

    private Client client;
}

public class Client
{
    // your usual Client class, its contents aren't important for the question
}

Say that I can have an order with ID 123, which belongs to client X. I can also have an order with ID 123 which belongs to client Y. When lazy loading (or eager loading, for that matter), how can I know that when I fetch order with ID 123 for client X from the database, I won't be getting the orderlines from client Y? If JPA checks on the foreign key on the orderline side only, is there a way to add a check for the client when lazy (or eager) loading?

I would like to solve this without using specific implementations like Hibernate or Eclipselink so I can easily switch between implementations if necessary.

Stefan
  • 1,433
  • 1
  • 19
  • 30
  • what check you want to make..? – Dileep Apr 01 '14 at 07:08
  • I would like a check for the client attribute, so I can fetch the orderlines what belong to order 123 and client X. – Stefan Apr 01 '14 at 07:09
  • you are saying that you need to fetch values based on both order id and client id..!! Am i correct ?? – Dileep Apr 01 '14 at 07:14
  • Ideally you do not care. When you access the list of orderLines, JPA will fetch it, if it has not yet. – Leos Literak Apr 01 '14 at 07:20
  • @Dileep That is correct. – Stefan Apr 01 '14 at 07:22
  • @LeosLiterak indeed, but how does JPA make a difference between order 123 with client X and order 123 with client Y? Both orders have the same ID's. – Stefan Apr 01 '14 at 07:23
  • @Stefan you can use `@Embedded` and `@AttributeOverrides` for that, detailed description here http://docs.jboss.org/hibernate/annotations/3.5/reference/en/html_single/#entity-mapping-property – Dileep Apr 01 '14 at 07:30
  • I miss some annotations over Client field in your code. Then JPA will add a condition. There is not id attribute either. – Leos Literak Apr 01 '14 at 07:30
  • Usually an ordering system does not produce the same order number for different orders. So it should not be possible for two client to have an order with the same order number. But if you must have that, you cannot simply search for an order number, you must search for order number and client number. – Seelenvirtuose Apr 01 '14 at 07:32
  • @LeosLiterak that would be a solution, but what annotations do I need for this? – Stefan Apr 01 '14 at 07:36
  • @Adrian was faster with his response and he is basicly correct. If he puts some code sample, it shall be sufficient for you. – Leos Literak Apr 01 '14 at 07:39
  • @Seelenvirtuose it can happen, as I receive orders from multiple systems. – Stefan Apr 01 '14 at 07:41
  • 1
    See my similar question, it contains pieces of code: http://stackoverflow.com/q/21647947/1639556 – Leos Literak Apr 01 '14 at 07:42

1 Answers1

2

Your choice of ID is probably not sufficient if you are just using the "ID (123)" as the ID of the Order entity.

In JPA, each entity should have a unique identifier. If there are going to be two Orders (one for X and one for Y) using the same ID, then everything is messed up.

My personal recommendation is to make ID unique across the whole system. If you want some kind of sequence number per client, keep it as another field.

Of course, there is another choice of making Client ID and Order ID as a composite key.

In short, make sure your choice of ID can uniquely identify an entity (usually means, a row in DB).

An example (First approach, unique ID)

public class Order
{
    @Id
    private Long id;

    @OneToMany(targetEntity = Orderline.class, fetch = FetchType.LAZY)
    private List<Orderline> orderlines;

    private Client client;

    private Long orderSequence;  // unique within a client
}

public class Orderline
{
    @Id
    private Long id;   // unique ID of order line

    @ManyToOne(mappedBy = 'orderlines')
    private Order order;

    // not necessary, as you can access through orderLine.order.client
    // private Client client;
}

Second approach (Composite key):

public class Order
{
    @EmbeddedId
    private OrderId id;

    @ManyToOne
    @JoinColumn(insertable=false, updatable=false)
    private Client client;

    @Column(insertable=false, updatable=false)
    private Long orderSequence;  // unique within a client

    @OneToMany(targetEntity = Orderline.class, fetch = FetchType.LAZY)
    private List<Orderline> orderlines;
}

@Embeddable
public class OrderId {
    Long clientId;
    Long orderSequence;
}
Adrian Shum
  • 38,812
  • 10
  • 83
  • 131
  • I haven't considered some kind of sequence yet, that sounds like a viable solution. Thanks! – Stefan Apr 01 '14 at 07:59