Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [eclipselink-users] Thorny JPA @OneToMany + @Generated + @EmbeddedId question

Hi Laird,

JPA 2.0 should cover the case you are looking at. It adds a feature called Derived Identifiers that supports having the id as part of a relationship.

  Here is one example from the spec:

@Entity
public class Employee {
@Id long empId;
String name;
...
}

public class DependentId {
String name; // matches name of @Id attribute
long emp; // matches name of @Id attribute and type of Employee PK
}

@Entity
@IdClass(DependentId.class)
public class Dependent {
@Id String name;
@Id @ManyToOne Employee emp;
...
}

There is more explanation about how these ids work in the spec in section 2.4.1. You can get the Proposed final draft here:

http://www.jcp.org/en/jsr/detail?id=317

This behavior is already implemented in the EclipseLink trunk code base (our 2.x development stream)

-Tom


Laird Nelson wrote:
My apologies if there is a better place to ask this; I figured that since this will be the JPA 2.0 reference implementation I'd start here.

I have a Person object that I'd like to link with a Map of Addresses, indexed by a String type. I'd also like to allow a given Address to be shared between Persons.

That suggests that an Address should have an owner Person, and a type field, and that the conjunction of the type and the owner's ID should form its primary key.

So:

Person
------
personID (PK; auto generated)
various other fields

Address
-------
personID (1/2 of PK and FK to Person.personID)
type (other 1/2 of PK)
various other fields

These would be represented by relationships like this:

(in Person.java:)
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long personID;

@OneToMany(mappedBy = "owner")
private Map<AddressPK, Address> addresses;

(in Address.java:)
@EmbeddedId
private PK pk;

@ManyToOne
@JoinColumn(name = "personID")
private Person owner;

@Embeddable
public static class PK implements Serializable {
  @Column(name = "type")
  String type;
  @Column(name = "personID")
  long personID;
}

If I create a new Person, add an Address to him under a given type, and then ask an EntityManager to persist the Person graph--and if I've annotated the Address relationship to cascade, of course--then I'd want the graph to persist. But at the moment, it doesn't do that, and I don't see an obvious way to enable this relatively common use case to happen.

If I try to persist the graph, then when it comes time to persist the dependent object (the Address) it does not have enough information to fill in the Address#pk#personID field, because at insert time it does not have a PK (since it's generated by the database). Consequently, EclipseLink (and Hibernate, and OpenJPA) try to insert NULL for the personID column in the Address table, which fails, correctly.

What I'd like to have happen is two things, really:

    * I'd like to use the owner property (the @ManyToOne relationship)
      as 1/2 of a primary key for the Address entity, and its type field
      for the other half.
    * I'd like the ORM tool to somehow use the generated Person ID when
      inserting the Address entity instead of NULL.

What's the expected behavior here, and/or what's the appropriate recipe to accomplish this?

I'm happy to clarify if anything in here is confusing.

Best,
Laird


------------------------------------------------------------------------

_______________________________________________
eclipselink-users mailing list
eclipselink-users@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/eclipselink-users


Back to the top