persistence@glassfish.java.net

RE: part of an embedded object is read-only...

From: Gordon Yorke <gordon.yorke_at_oracle.com>
Date: Tue, 8 Aug 2006 16:41:54 -0400

Hello,
    The OneToOne mapping should be the mapping within the primaryKeyMappings in this case, as that is the only attribute that can be trusted to have the correct value in it as it is the only writable mapping.
    Support for non-writable PK's could be added but I think it would be limited in value as it would prevent creation of entities as a side effect.
--Gordon
  -----Original Message-----
  From: Wonseok Kim [mailto:guruwons_at_gmail.com]
  Sent: Tuesday, August 08, 2006 3:32 AM
  To: persistence_at_glassfish.dev.java.net
  Subject: Re: part of an embedded object is read-only...


  When I see the code AggregateObjectMapping's readOnly flag is always set false so isReadOnly() seems to be meaningless.
  I think it needs to check each field of AggregateObjectMapping for read-only. Following can be one solution.

  public void initialize(AbstractSession session) throws DescriptorException {
  ...
              // Add field to mapping association
              for (Enumeration fields = mapping.getFields().elements(); fields.hasMoreElements();) {
  // Object field = fields.nextElement();
                  DatabaseField field = (DatabaseField) fields.nextElement();//field is always DatabaseField
                  if (!mapping.isReadOnly() && !field.isReadOnly()) {//PATCH: if AggregateObjectMapping check if each field is read-only
                      if (getMappingsByField().containsKey(field)) {
                          // We cannot determine if aggregate mapping for the field are read-only, so ignore exception.
                          if (!mapping.isAggregateObjectMapping()) {
                              session.getIntegrityChecker().handleError(DescriptorException.multipleWriteMappingsForField(field.toString(), mapping));
                          }
  ...

  But this causes another problem in initializePrimaryKey() for Embedded object which has read-only primary key like Sahoo's sample.

  @Entity
  public class Table1 implements java.io.Serializable {

  @EmbeddedId
  protected Table1PK table1PK;

  @JoinColumn(name = "ID", referencedColumnName = "ID")
  @OneToOne
  private Table2 table2;
  ...

  @Embeddable
  public class Table1PK implements java.io.Serializable {

  @Column(name = "ID", nullable = false, insertable=false, updatable=false)
  private int id;
  ...

  In initializePrimaryKey() it find and set primaryKeyMappings from mappingsByField map which contains non-read-only mappings. So if embedded object has read-only primary key, its AggregateObjectMapping can not be found and put into primaryKeyMappings.
  Instead another mapping OneToOneMapping is found and put into primaryKeyMappings incorrectly(so cause problem later).

  Basically I wonder that TopLink can handle read-only primary key mapping properly, because when I have following mapping in another sample:

    @Id
    @Column(name="ID", insertable = false, updatable = false)
    public int id;

  it throws following exception:

  Exception Description: There should be one non-read-only mapping defined for the primary key field [ TABLE1.ID].
  Descriptor: RelationalDescriptor(Table1 --> [DatabaseTable(TABLE1)])

  So IMHO to fix the issue we need to be clear about read-only primary key first.

  -Wonseok


  On 8/7/06, Sanjeeb Kumar Sahoo <Sanjeeb.Sahoo_at_sun.com> wrote:
    (Resending as the earlier email which had a wrong subject.)

    Hi Tom, Gordon,

    I am looking into issue
    https://glassfish.dev.java.net/issues/show_bug.cgi?id=894 . Looking at
    the code I see that the metadata processing code is correctly processing
    the insertable and updatable values that are specified in the Embeddable
    class. An *AggregateObjectMapping* type of mapping is also created for
    the embedded field. The bug seem to be in ObjectBuilder.java which is
    reporting an incorrect exception. See code below from ObjectBuilder.java:
        public void initialize(AbstractSession session) throws
    DescriptorException {
                ...
                    if (!mapping.isReadOnly()) {
                        if (getMappingsByField().containsKey(field)) {
                            // We cannot determine if aggregate mapping for
    the field are read-only, so ignore exception.
                            if (!mapping.isAggregateObjectMapping()) {

    session.getIntegrityChecker().handleError(DescriptorException.multipleWriteMappingsForField(field.toString(),
    mapping));
                            }
                        }
                ...

    As you can see, from the above code, it is checking if the
    AggregateObjectMapping is readonly or not. Should it not instead check
    individual mapping objects that are part of the AggregateObjectMapping?
    What I don't understand is why is their a boolean type field called
    *isReadOnly* on an AggregateObjectMapping. What is the semantics of that
    boolean flag? /Does TopLink Essential not support a part of an embedded
    object to be read-only?/

    Thanks,
    Sahoo




  --
  Wonseok Kim
  Senior Developer, TmaxSoft