论坛首页 Java企业应用论坛

使用JPA注解,持久化java.util.Map!

浏览 3336 次
该帖已经被评为隐藏帖
作者 正文
   发表时间:2010-02-16  
Using annotations to persist java.util.Maps

转自:http://www.jroller.com/eyallupu/entry/using_annotations_to_persist_java

Mapping any kind of collections is quite simple, @OneToMany on the inverse side, @ManyToOne on the owning side and it works (usually). Maps are little bit more complicated, and less intuitive. Suppose that I want to add to a customer entity a map of properties, each property has a name (the map's key) and a value. Something like:

   private Map<String,String> attributes;


Looks simple, isn't that? Yes but currently (as far as I can understand the documentation) there is no support for “true/real maps” the specification only defines support of maps in which the map's key is a property from the map's value. It means that if I want to map the customer's attributes then I have to create a new entity, with three properties

The attribute key (which will be used s the Map's key)

The attribute value

And an Id (since this is an entity)

Then I can map it on the customer class using the @OneToMany and @MapKey annotations.

The Attribute class

package par.common;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;

@Entity
public class Attribute implements Serializable {

/**
* SUID
*/
private static final long serialVersionUID = 3581307841164176872L;

@Id
@GeneratedValue(strategy = GenerationType.TABLE)
int id;

public String attrKey;

public String value;

@ManyToOne
Customer customer;

public Attribute(String one, String two, Customer customer) {
this.attrKey = one;
this.value = two;
this.customer = customer;
}

          //A public default constructor is mandatory!!
public Attribute() {
}

public Customer getCustomer() {
return customer;
}

public void setCustomer(Customer customer) {
this.customer = customer;
}

public String getValue() {
return value;
}

public void setValue(String value) {
this.value = value;
}

public String getAttrKey() {
return attrKey;
}

public void setAttrKey(String attrKey) {
this.attrKey = attrKey;
}
}

@ManyToOne

The @ManyToOne annotation of the customer field tells the entity manager that many attributes can be linked to one customer (M:1). On a parent-children relation this is the children end of the relation. This is also considered to be the owning side of the relation, in this side the actual relation is stored in the database (the customer property is the owner of the relation). The other side on the relation - the customer's side - is the inverse side, to fetch all of its sons the customer (the inverse side) has to access the attributes' table (the owning side).

And the field and property mappings of the Customer class:


        
         private Map<String, Attribute> attributes = new HashMap<String, Attribute>(10);

      
@OneToMany(mappedBy="customer",cascade = CascadeType.ALL)
@MapKey(name = "attrKey")
public Map<String, Attribute> getAttributes () {
return attributes;
}

public void setAttributes (Map<String, Attribute> attributes) {
this. attributes  = attributes;
}


@OneToMany

The @oneToMany annotation specifies that a customer might have many attributes linked to, the “mappedBy” parameter of the annotation tells the entity manager what is the property/field name that owns the relation. Since this is the inverse side of the relation the ORM has to be notified about the property, on the owning side of the relation, that owns the relation.

@MapKey

This annotation specifies what is the map of the key, it has one parameter – 'name'. The name should be a valid property name from the entity in the map, empty (which implies to the PK of the entity, this is the default). When the entity manager loads a a java.util.Map mapped relation, each entity stored in the map using the MapKey property as its key.



Conclusions

We can use JEE EJB3 specification to persist maps, but we have to notice that the mapping is not as straight forward as we would expect it to be, for example to get the value of an attribute I would have to

   String attrValue = customer.getAttributes().get(attrKey).getValue();
But this can be wrapped in a method inside the Customer class.

Posted at 10:48AM Feb 10, 2006 by Eyal Lupu in Persistence  |  Comments[2]

Comments:

Very useful example. Thanks!
Posted by Stephen M on April 14, 2006 at 11:26 PM GMT+02:00 #

Great article!
Do you know how is the mapping influenced if you have subclasses of the Attribute class, and for example want to store the super class instances with sub classes inside the Map?

Thanks!
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics