Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Excluding fields from @Embedded properties on case by case basis with Hibernate/JPA

I am migrating some classes in a Hibernate hbm.xml file to JPA annotations.

We have an embeddable class Address that is used in several places. Each place uses a different subset of the properties in Address.

(getters/setters omitted for brevity)

@Embeddable
public class Address {
  String email;
  String address;
  String city; 
  String state;
  String zip;
  String country;
}

@Entity
@Table(name="customer")
public class Customer {
  @Embedded
  @AttributeOverrides({
    @AttributeOverride(name="address", column=@Column(name="ship_addr"),
    @AttributeOverride(name="city", column=@Column(name="ship_city"),
    @AttributeOverride(name="state", column=@Column(name="ship_state"),
    @AttributeOverride(name="zip", column=@Column(name="ship_zip"),
    @AttributeOverride(name="country", column=@Column(name="ship_country")
  })
  Address shippingAddress;

  @Embedded
  @AttributeOverrides({
    @AttributeOverride(name="address", column=@Column(name="bill_addr"),
    @AttributeOverride(name="city", column=@Column(name="bill_city"),
    @AttributeOverride(name="state", column=@Column(name="bill_state"),
    @AttributeOverride(name="zip", column=@Column(name="bill_zip")
  })
  Address billingAddress;
}

Note that in this contrived example, shippingAddress uses Address.country, but billingAddress does not; and neither of them use Address.email.

The problem is that Hibernate is inferring @Column tags for any column where I haven't explicitly provided one.

I tried adding @Transient to all the Address fields, but it appears that @AttributeOverride does not trump @Transient.

Is there any workaround for this?

like image 350
qualidafial Avatar asked Aug 10 '11 19:08

qualidafial


2 Answers

My advice would be to create a new entity called PartialAddress/NationalAddress/BillingAddress. This would be used only for the JPA mapping, and not exposed on the Customer interface:

private PartialAddress billingAddress;

public Address getBillingAddress() {
    return billingAddress.toAddress();
}

Otherwise, I have come up with a somewhat ugly workaround for this problem, maybe it will work for you as well. Instead of mapping the field to a real column, I return a SQL null constant:

@Embedded
@AttributeOverrides({
    @AttributeOverride(name="address", column=@Column(name="bill_addr"),
    @AttributeOverride(name="city", column=@Column(name="bill_city"),
    @AttributeOverride(name="state", column=@Column(name="bill_state"),
    @AttributeOverride(name="zip", column=@Column(name="bill_zip"),
    @AttributeOverride(name="country", column=@Column(name="bill_id + null"),
})
Address billingAddress;

I'm using Oracle and EclipseLink, works on Hibernate 3.6 as well. And I've only tested it on read-only objects. Though, theoretically, setting the insertable and updatable attributes to false should be enough.

like image 136
GFonte Avatar answered Oct 02 '22 03:10

GFonte


I don't think it is possible with annotations to "ignore" a field from address in your embedded objects.

A workaround is to create a base type Address without email and an ExtendedAddress (subclass of Address) with the field email.

like image 36
K.C. Avatar answered Oct 02 '22 05:10

K.C.