Hi Jeffrey,
Jeffrey Blattman wrote:
> hi marina,
>
> as i mentioned below, toplink complains if i include only the single
> @JoinColumn for ENTITY_ID and ENTITY_NAME.
>
> /Exception Description: The @JoinColumns on the annotated element
> [private com.sun.portal.pom.Entity com.sun.portal.pom.Preference.entity]
> from the entity class [class com.sun.portal.pom.Preference] is
> incomplete. W*hen the source entity class uses a composite primary key,
> a @JoinColumn must be specified for each join column using the
> @JoinColumns.* Both the name and the referenceColumnName elements must
> be specified in each such @JoinColumn.
> /
> as the message says and i indicated below i needed to add a @JoinColumn
> for each field of the composite ID.
Yes, if Entity has a composite ID. But then it seems that Entity's ID column
names do not match the ones that you reference.
>
> if i leave off the @JoinColumn/s all together it does work, but i want
> to specify the insertable and updatable = false setting and i assume
> those are not the defaults for a @ManyToOne mapped field.
Then just specify them without specifying the column names.
thanks,
-marina
>
> ?
>
> Marina Vatkina wrote:
>
>> Jeffrey,
>>
>> You @JoinColumn should reference the PK on the ENTITY table, which is
>> most probably just ENTITY_NAME.
>>
>> Now, if you use TopLink to generate the tables, you do not need the
>> mapping annotation at all - TopLink will do the right thing for you.
>>
>> Regards,
>> -marina
>>
>> Jeffrey Blattman wrote:
>>
>>> after playing with this some, i found the following works ... p.s.,
>>> note that i have an entity class w/ the name "Entity" ... so don't
>>> let that confuse you :)
>>>
>>> /_at_IdClass(com.sun.portal.pom.PreferenceId.class)
>>> @javax.persistence.Entity
>>> public class Preference implements Serializable {
>>> @Id
>>> @Column(name="PREFERENCE_NAME", nullable=false)
>>> private String name;
>>> @Id
>>> @Column(nullable = false, name="ENTITY_ID")
>>> private String entityId = null;
>>> @ManyToOne(optional = false, cascade = CascadeType.ALL)
>>> * @JoinColumns({
>>> @JoinColumn(insertable=false, updatable=false,
>>> nullable=false, name="ENTITY_ID", referencedColumnName="ENTITY_NAME"),
>>> @JoinColumn(insertable=false, updatable=false,
>>> nullable=false, name="PREFERENCE_NAME",
>>> referencedColumnName="PREFERENCE_NAME")
>>> })
>>> * private Entity entity;/
>>>
>>> i am however seeing this at runtime ...
>>>
>>> /[TopLink Warning]: 2007.08.06
>>> 03:37:48.226--ServerSession(4926903)--Exception [TOPLINK-4002]
>>> (Oracle TopLink Essentials - 2.0 (Build 56 (07/18/2007))):
>>> oracle.toplink.essentials.exceptions.DatabaseException
>>> Internal Exception: java.sql.SQLException: Constraint
>>> 'PREFERENCEENTITYID' is invalid: there is no unique or primary key
>>> constraint on table 'APP.ENTITY' that matches the number and types of
>>> the columns in the foreign key.
>>> Error Code: -1
>>> Call: ALTER TABLE PREFERENCE ADD CONSTRAINT PREFERENCEENTITYID
>>> FOREIGN KEY (ENTITY_ID, PREFERENCE_NAME) REFERENCES ENTITY
>>> (ENTITY_NAME, PREFERENCE_NAME)
>>> /
>>> not sure if it is related?
>>>
>>> Jeffrey Blattman wrote:
>>>
>>>> hi again markus,
>>>>
>>>> Markus Fuchs wrote:
>>>>
>>>>> Hi Jeffrey,
>>>>>
>>>>> Jeffrey Blattman wrote:
>>>>>
>>>>>> thanks markus,
>>>>>>
>>>>>> this gets me further. the complexity is this, i essentially have
>>>>>> three entities
>>>>>>
>>>>>> 1. Page
>>>>>> 2. Portlet
>>>>>> 3. Preferenence
>>>>>>
>>>>>> simple right? a page contains a portlet contains preferences. a
>>>>>> delete / update / etc of Page should affect all its portlets, and
>>>>>> a delete / update / etc of a portlet should affect its
>>>>>> preferences. each of these has a name.
>>>>>>
>>>>>> to model the containment, Portlet's ID is the page name + it's own
>>>>>> name (PortletId). that one is simple. however, when we go a level
>>>>>> deeper to Preference, Preference's ID is the Portlet's ID + it's
>>>>>> own name (PreferenceId).
>>>>>>
>>>>>> how do i model that? PortletId is *not* a simple type, so I can't
>>>>>> use it as an @Id field in Preference. how do i define Preference's
>>>>>> ID fields?
>>>>>>
>>>>> Id fields:
>>>>>
>>>>> In page: pageId
>>>>> In Portlet: pageId & portletId, IdClass has pageId & portletId fields
>>>>> In preference: pageId & portletId & preferenceId, IdClass has
>>>>> pageId & portletId & preferenceId fields
>>>>
>>>>
>>>> so the general ID is that each "contained" entity needs to have
>>>> simple typed ID fields for every containing entity class.
>>>>
>>>> this is sort of confusing, because it means that a Preference needs
>>>> to know about pages, when ideally all it would care about is the
>>>> containing entity above it. but i think i get it. for example, as
>>>> long as a Portlet has a unique ID, why does a Preference needs to
>>>> know or care about the Page? the Portlet has already encapsulated
>>>> the Page ID into it's ID, why does it need to be exposed to the
>>>> Preference?
>>>>
>>>>>
>>>>>> when i just make it a @JoinColumn instead,
>>>>>>
>>>>>> / @ManyToOne(optional = false, cascade = CascadeType.ALL)
>>>>>> @Column(insertable=false, updatable=false, nullable=false,
>>>>>> name="PORTLET_ID")
>>>>>> @XmlTransient
>>>>>> private Portlet portlet;
>>>>>>
>>>>>> /i get this ...
>>>>>>
>>>>>> /Exception Description: The @JoinColumns on the annotated element
>>>>>> [private com.sun.portal.pom.Entity
>>>>>> com.sun.portal.pom.Preference.entity] from the entity class [class
>>>>>> com.sun.portal.pom.Preference] is incomplete. W*hen the source
>>>>>> entity class uses a composite primary key, a @JoinColumn must be
>>>>>> specified for each join column using the @JoinColumns.* Both the
>>>>>> name and the referenceColumnName elements must be specified in
>>>>>> each such @JoinColumn.
>>>>>> /
>>>>>
>>>>>
>>>>> Looks like you used /_at_JoinColumn*s*. Please check.
>>>>>
>>>>> /
>>>>
>>>>
>>>> no, i didn't. the message is telling me that i need to specify >1
>>>> @JoinColumn's, and use a @JoinColumns to contain them. i think.
>>>>
>>>> i eventually got something that appears to work, on TopLink. i had
>>>> to remove the @JoinColumn from the @ManyToOne in Preference and
>>>> Portlet. this is course means i'm missing insertable and updatable =
>>>> false settings.
>>>>
>>>>>> what am i supposed to use for the join columns? since PortletId
>>>>>> encapsulates both the Page name and Portlet name, why does it want
>>>>>> to to specify more than that?
>>>>>>
>>>>>> i feel like i must be making this more complicated than it needs
>>>>>> to be. all i want is to model some objects containing other
>>>>>> objects where all operations cascade.
>>>>>>
>>>>> This should be doable. First start with the Page and Portlet
>>>>> classes. When this works, add Preferences and model the
>>>>> relationships and IdClass accordingly.
>>>>>
>>>> i know the 2-level case works. the 3 level case is giving me trouble
>>>> because i have a composite ID that has (at least conceptually)
>>>> another composite ID as a field.
>>>>
>>>>> -- markus.
>>>>>
>>>>>> ?
>>>>>>
>>>>>> Markus Fuchs wrote:
>>>>>>
>>>>>>> Hi Jeffrey,
>>>>>>>
>>>>>>> Entities should not use relationship fields as part of the
>>>>>>> primary key. The JPA spec says (please see 2.1.4.):
>>>>>>>
>>>>>>> The primary key (or field or property of a composite primary key)
>>>>>>> should be one of the following types:
>>>>>>> any Java primitive type; any primitive wrapper type;
>>>>>>> java.lang.String; java.util.Date;
>>>>>>> java.sql.Date.
>>>>>>>
>>>>>>> Try changing:
>>>>>>>
>>>>>>> public abstract class Entity implements Serializable {
>>>>>>> @Id
>>>>>>> @Column (nullable = false, name="ENTITY_NAME")
>>>>>>> @XmlAttribute
>>>>>>> private String name;
>>>>>>>
>>>>>>> @Id
>>>>>>> @Column (nullable = false, name="PAGE_ID") private
>>>>>>> String pageId;
>>>>>>>
>>>>>>>
>>>>>>> @Column (nullable = false, name="PAGE_ID") @ManyToOne
>>>>>>> (cascade = CascadeType.ALL, insertable=false, updatable=false)
>>>>>>> private Page page = null;
>>>>>>> ...
>>>>>>> }
>>>>>>>
>>>>>>> public class EntityId implements Serializable {
>>>>>>> private String name;
>>>>>>> private String pageId;
>>>>>>> ...
>>>>>>> }
>>>>>>>
>>>>>>>
>>>>>>> -- markus.
>>>>>>>
>>>>>>> Entity
>>>>>>> Jeffrey Blattman wrote:
>>>>>>>
>>>>>>>> hi,
>>>>>>>>
>>>>>>>> 2.0-b56, i'm seeing this ...
>>>>>>>>
>>>>>>>> /Exception Description: Invalid composite primary key
>>>>>>>> specification. The names of the primary key fields or properties
>>>>>>>> in the primary key class [com.sun.portal.pom.EntityId] and those
>>>>>>>> of the entity bean class [class com.sun.portal.pom.Entity] must
>>>>>>>> correspond and their types must be the same. Also, ensure that
>>>>>>>> you have specified id elements for the corresponding attributes
>>>>>>>> in XML and/or an @Id on the corresponding fields or properties
>>>>>>>> of the entity class.
>>>>>>>> /
>>>>>>>> i've attached the two classes. Entity has IDs /name/ and /page/,
>>>>>>>> and EntityId has fields /name/ and /page/. same name, same type.
>>>>>>>> i can zip the maven2 project so the problem can be reproduced,
>>>>>>>> if that helps.
>>>>>>>>
>>>>>>>> what am i missing?
>>>>>>>>
>>>>>>>> thanks.
>>>>>>>
>>>>>>>
>>