Managed Relationships

They may be some confusion in regards to Managed Relationships and that some vendors don't "believe" in this approach. Ebean does provide some automatic relationship management in the belief that it makes life simpler for Developers so a quick explanation is required.


...
@Entity
class Order

  @OneToMany(cascade=CascadeType.ALL)
  List<OrderDetail> details;

  public List<OrderDetail> getDetails() {
    return details;
  }

  public void setDetails(List<OrderDetail> details) {
    this.details = details;
  }
...
}

...
@Entity
class OrderDetail {
...
  @ManyToOne
  Order order;

  public Order getOrder() {
    return order;
  }

  public void setOrder(Order order) {
    this.order = order;
  }
}



The example above is a typical relationship you will see often. Note that the cascade ALL is on the details so that if the order is saved its details are saved as well (via cascading).

Ebean sets the order to orderdetail just prior to save

What happens here is that when the order is saved and we cascade down to save the details, we iterate through each detail and save the detail. Just prior to saving each detail Ebean will automatically set the "master" order to the "detail" orderDetail (but only if the detail is "dirty" and will be saved).


  Order newOrder = new Order();
  newOrder.setCustomer(customer);
  ...

  ArrayList details = new ArrayList();
  // set the details list to newOrder
  newOrder.setDetails(details);

  OrderDetail line = new OrderDetail();
  line.setProduct(prod);
  line.setQuantity(10);

  // relate orderDetail back to order
  // this is optional as Ebean will do this
  // for you automatically on save
  line.setOrder(newOrder);

  details.add(line);

  line = new OrderDetail();
  ...
  details.add(line);


  Ebean.save(newOrder);

Just prior to saving a 'detail' Ebean will set the order to the orderDetail.

Alternative: using a convienience method

Below is a method added to Order to provide a way to manage the Order - OrderDetail relationship. This is a method suggested by some but I am not convinced about its merits.

It has potential issues with NullPointerException and firing Lazy Loading so if you go down this route you need to think about those issues.


...
@Entity
class Order {
...

  public void addOrderDetail(OrderDetail line) {
    if (line == null) {
      throw new IllegalArgumentException("line is null?");
    }
    if (line.getOrder() != null) {
      line.getOrder().getDetails().remove(line);
    }
    line.setOrder(this);
    details.add(childCategory);
  }


In adding such a method some may suggest that the setDetails() method become private. It should be noted that if setDetails is private then you can not control the construction of the details. Specifically you lose the ability to control the details query yourself and set those results into the Order.


  Order order = ...

  // set the details using your own query
  FindByPredicates find = new FindByPredicates();
  find.setBeanType(OrderDetail.class);
  find.add("order_id", find.EQ, order.getId());
  find.addAnd();
  find.add("status_code", find.EQ, "DISPUTE");

  List disputedDetails = Ebean.findList(find);

  ...
  order.setDetails(disputedDetails);


Introduction User Guide (pdf) Install/Configure Public JavaDoc Whitepapers
General Database Specific Byte Code Deployment Annotations Features
Top Bugs Top Enhancements
woResponse