Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » EclipseLink » @EmbeddedId in conjunction with InheritanceType.JOINED does not generate PK-Field
@EmbeddedId in conjunction with InheritanceType.JOINED does not generate PK-Field [message #728691] Fri, 23 September 2011 16:45 Go to next message
Hannes  is currently offline Hannes
Messages: 11
Registered: September 2011
Junior Member
Hello,

I have a class, using @EmbeddedId as primary key:

@Entity
@Inheritance(strategy=InheritanceType.JOINED)
@Table(name="PAE")
@DiscriminatorColumn(name="DTYPE", discriminatorType=DiscriminatorType.STRING,length=20)
@DiscriminatorValue("R")
public class PersistentAccountancyEntry implements AccountancyEntry {
	@EmbeddedId
	@AttributeOverride(name="id", column=@Column(name="ENTRY_ID"))
	private AccountancyEntryIdentifier accountancyEntryIdentifier;


And a subclass of that class:


@Entity
@Table(name="PPE")
@DiscriminatorValue("P")
public class ProductPaymentEntry extends PersistentAccountancyEntry
{
	@Embedded
	@AttributeOverride(name = "id", column = @Column(name = "ORDER_ID"))
	private OrderIdentifier orderIdentifier;

	@Embedded
	@AttributeOverride(name = "id", column = @Column(name = "UID"))
	private UserIdentifier userIdentifier;


Which results in tables being generated as follows:

[EL Fine]: Connection(941535430)--DROP TABLE PAE
[EL Fine]: Connection(941535430)--CREATE TABLE PAE (DTYPE VARCHAR(20), DATE TIMESTAMP, DESCRIPTION VARCHAR(255), VALUE BLOB(2147483647), ENTRY_ID VARCHAR(255))
[EL Fine]: Connection(941535430)--DROP TABLE PPE
[EL Fine]: Connection(941535430)--CREATE TABLE PPE (ENTRY_ID VARCHAR(255) NOT NULL, ORDER_ID VARCHAR(255), UID VARCHAR(255) NOT NULL, PRIMARY KEY (ENTRY_ID, UID))


Notably, ENTRY_ID is not a primary key field on table PAE, instead the table PPE has a composite primary key of ENTRY_ID and UID. UID is just a foreign key, not a composite primary key. (OrderIdentifier is an @EmbeddedId in an entirely different class.)
All this would matter much, but some queries fail:

	EntityManager em = emf.createEntityManager();
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<PersistentAccountancyEntry> q = cb
				.createQuery(PersistentAccountancyEntry.class);
		Root<PersistentAccountancyEntry> r = q
				.from(PersistentAccountancyEntry.class);
		Predicate p = cb.between(r.get(PersistentAccountancyEntry_.date),
				from.toDate(), to.toDate());
		q.where(p);
		TypedQuery<PersistentAccountancyEntry> tq = em.createQuery(q);


[EL Warning]: 2011-09-23 18:38:44.388--UnitOfWork(1237880619)--Exception [EclipseLink-6044] (Eclipse Persistence Services - 2.3.0.v20110604-r9504): org.eclipse.persistence.exceptions.QueryException
Exception Description: The primary key read from the row [ArrayRecord(
	PAE.DTYPE => R
	PAE.DATE => 2011-09-23 18:38:37.219
	PAE.DESCRIPTION => null
	PAE.VALUE => [B@6153e0c0
	PAE.ENTRY_ID => 45aabaaf-cf87-4261-b0b0-f13a8b5e5ead)] during the execution of the query was detected to be null.  Primary keys must not contain null.
Query: ReadAllQuery(referenceClass=PersistentAccountancyEntry sql="SELECT DISTINCT DTYPE FROM PAE WHERE (DATE BETWEEN ? AND ?)")


Now, ENTRY_ID should be the primary key field, and it is obviously not null. What am I doing wrong?
Re: @EmbeddedId in conjunction with InheritanceType.JOINED does not generate PK-Field [message #729594 is a reply to message #728691] Mon, 26 September 2011 15:33 Go to previous messageGo to next message
James Sutherland is currently offline James Sutherland
Messages: 1939
Registered: July 2009
Location: Ottawa, Canada
Senior Member

Include the AccountancyEntryIdentifier source.


James : Wiki : Book : Blog : Twitter
Re: @EmbeddedId in conjunction with InheritanceType.JOINED does not generate PK-Field [message #731246 is a reply to message #729594] Fri, 30 September 2011 11:30 Go to previous messageGo to next message
Hannes  is currently offline Hannes
Messages: 11
Registered: September 2011
Junior Member
Thank you for looking into this. AccountancyEntryIdentifier is a subclass of SalespointIdentifier. Here is the (relevant) Code for both classes. (toString(), equals(), hashcode() etc omitted for brevity)

@SuppressWarnings("serial")
@Embeddable
@MappedSuperclass
public class SalespointIdentifier implements Serializable, Comparable<SalespointIdentifier>
{
	private String id;

	public SalespointIdentifier()
	{
		id = UUID.randomUUID().toString();
	}
...
}


@SuppressWarnings("serial")
@Embeddable
public final class AccountancyEntryIdentifier extends SalespointIdentifier {
	public AccountancyEntryIdentifier() {
		super();
	}

	@Deprecated
	public AccountancyEntryIdentifier(String identifier) {
		super(identifier);
	}
}


Both, UserIdentifier and OrderIdentifier subclass SalespointIdentifier in the same manner as AccountancyEntryIdentifier. The sole purpose of this class hierarchy is type-safety, when handling identifier/primary keys.
Re: @EmbeddedId in conjunction with InheritanceType.JOINED does not generate PK-Field [message #731248 is a reply to message #729594] Fri, 30 September 2011 11:30 Go to previous messageGo to next message
Hannes  is currently offline Hannes
Messages: 14
Registered: March 2011
Junior Member
Thank you for looking into this. AccountancyEntryIdentifier is a subclass of SalespointIdentifier. Here is the (relevant) Code for both classes. (toString(), equals(), hashcode() etc omitted for brevity)


@SuppressWarnings("serial")
@Embeddable
@MappedSuperclass
public class SalespointIdentifier implements Serializable, Comparable<SalespointIdentifier>
{
private String id;

public SalespointIdentifier()
{
id = UUID.randomUUID().toString();
}
...
}



@SuppressWarnings("serial")
@Embeddable
public final class AccountancyEntryIdentifier extends SalespointIdentifier {
public AccountancyEntryIdentifier() {
super();
}

@Deprecated
public AccountancyEntryIdentifier(String identifier) {
super(identifier);
}
}


Both, UserIdentifier and OrderIdentifier subclass SalespointIdentifier in the same manner as AccountancyEntryIdentifier. The sole purpose of this class hierarchy is type-safety, when handling identifier/primary keys.
Re: @EmbeddedId in conjunction with InheritanceType.JOINED does not generate PK-Field [message #731980 is a reply to message #731248] Mon, 03 October 2011 15:28 Go to previous messageGo to next message
James Sutherland is currently offline James Sutherland
Messages: 1939
Registered: July 2009
Location: Ottawa, Canada
Senior Member

I do not believe that you can use MappedSuperclass on an Embeddable. Try removing this and remove the identifier inheritance.


James : Wiki : Book : Blog : Twitter
Re: @EmbeddedId in conjunction with InheritanceType.JOINED does not generate PK-Field [message #732347 is a reply to message #731980] Tue, 04 October 2011 14:52 Go to previous messageGo to next message
Hannes  is currently offline Hannes
Messages: 11
Registered: September 2011
Junior Member
I removed the InheritanceStrategy, so the table generation defaults to single table. This seems to work, if all @EmbeddedIds and @Embeddables are annotated with @AttributeOverrides.

The code now looks like:

@Entity
public class PersistentAccountancyEntry implements AccountancyEntry {
	@EmbeddedId
	@AttributeOverride(name = "id", column = @Column(name = "ENTRY_ID", nullable = false))
	private AccountancyEntryIdentifier accountancyEntryIdentifier = new AccountancyEntryIdentifier();
...


@Entity
public class ProductPaymentEntry extends PersistentAccountancyEntry {
	/**
	 * The <code>OrderIdentifier</code> to which this
	 * <code>ProductPaymentEntry</code> refers to.
	 */
	@Embedded
	@AttributeOverride(name = "id", column = @Column(name = "ORDER_ID", nullable = true))
	private OrderIdentifier orderIdentifier;

	/**
	 * The <code>UserIdentifier</code> to which this
	 * <code>ProductPaymentEntry</code> refers to.
	 */
	@Embedded
	@AttributeOverride(name = "id", column = @Column(name = "USER_ID", nullable = true))
	private UserIdentifier userIdentifier;
...


Resulting in:

[EL Fine]: Connection(1085171660)--CREATE TABLE PERSISTENTACCOUNTANCYENTRY (DTYPE VARCHAR(31), DATE TIMESTAMP, DESCRIPTION VARCHAR(255), VALUE BLOB(2147483647), ENTRY_ID VARCHAR(255) NOT NULL, PAYMENTMETHOD BLOB(2147483647), ORDER_ID VARCHAR(255), USER_ID VARCHAR(255), PRIMARY KEY (ENTRY_ID))


It seems using @Embeddable annotation and @MappedSuperclass simultaneously allows for correct @Embeddable inheritance in this scenario. Removing the identifier hierarchy results in a lot of code duplication for equals() and hashcode() methods of the identifiers, which I would like to avoid. SalespointIdentifier should be used as PK itself (@EmbeddableId); this is why it is annotated with @Embeddable. And with the @MappedSuperclass annotation, sub class instances, annotated with @Embedded generate also columns (which does not work otherwise).
Re: @EmbeddedId in conjunction with InheritanceType.JOINED does not generate PK-Field [message #732821 is a reply to message #731980] Tue, 04 October 2011 14:52 Go to previous messageGo to next message
Hannes  is currently offline Hannes
Messages: 14
Registered: March 2011
Junior Member
I removed the InheritanceStrategy, so the table generation defaults to single table. This seems to work, if all @EmbeddedIds and @Embeddables are annotated with @AttributeOverrides.

The code now looks like:


@Entity
public class PersistentAccountancyEntry implements AccountancyEntry {
@EmbeddedId
@AttributeOverride(name = "id", column = @Column(name = "ENTRY_ID", nullable = false))
private AccountancyEntryIdentifier accountancyEntryIdentifier = new AccountancyEntryIdentifier();
...



@Entity
public class ProductPaymentEntry extends PersistentAccountancyEntry {
/**
* The <code>OrderIdentifier</code> to which this
* <code>ProductPaymentEntry</code> refers to.
*/
@Embedded
@AttributeOverride(name = "id", column = @Column(name = "ORDER_ID", nullable = true))
private OrderIdentifier orderIdentifier;

/**
* The <code>UserIdentifier</code> to which this
* <code>ProductPaymentEntry</code> refers to.
*/
@Embedded
@AttributeOverride(name = "id", column = @Column(name = "USER_ID", nullable = true))
private UserIdentifier userIdentifier;
...


Resulting in:


[EL Fine]: Connection(1085171660)--CREATE TABLE PERSISTENTACCOUNTANCYENTRY (DTYPE VARCHAR(31), DATE TIMESTAMP, DESCRIPTION VARCHAR(255), VALUE BLOB(2147483647), ENTRY_ID VARCHAR(255) NOT NULL, PAYMENTMETHOD BLOB(2147483647), ORDER_ID VARCHAR(255), USER_ID VARCHAR(255), PRIMARY KEY (ENTRY_ID))


It seems using @Embeddable annotation and @MappedSuperclass simultaneously allows for correct @Embeddable inheritance in this scenario. Removing the identifier hierarchy results in a lot of code duplication for equals() and hashcode() methods of the identifiers, which I would like to avoid. SalespointIdentifier should be used as PK itself (@EmbeddableId); this is why it is annotated with @Embeddable. And with the @MappedSuperclass annotation, sub class instances, annotated with @Embedded generate also columns (which does not work otherwise).
Re: @EmbeddedId in conjunction with InheritanceType.JOINED does not generate PK-Field [message #734058 is a reply to message #732347] Thu, 06 October 2011 14:36 Go to previous message
James Sutherland is currently offline James Sutherland
Messages: 1939
Registered: July 2009
Location: Ottawa, Canada
Senior Member

I agree that EclipseLink should support inheritance with Embeddables, please log a bug and vote for it. Actually the EclipseLink API supports inheritance with embeddables, it is just the JPA annotations that do not support it.

James : Wiki : Book : Blog : Twitter
Previous Topic:soft delete is deleting relations
Next Topic:Parameterized PersistenceContext in EJB 3.1
Goto Forum:
  


Current Time: Fri Oct 24 10:33:35 GMT 2014

Powered by FUDForum. Page generated in 0.14672 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software