Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 322233 - "Multiple writable mappings exist" when using AttributeOverrides and AssociationOverride
Summary: "Multiple writable mappings exist" when using AttributeOverrides and Associat...
Status: CLOSED FIXED
Alias: None
Product: z_Archived
Classification: Eclipse Foundation
Component: Eclipselink (show other bugs)
Version: unspecified   Edit
Hardware: PC Linux
: P2 normal (vote)
Target Milestone: ---   Edit
Assignee: Nobody - feel free to take it CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-08-10 09:47 EDT by Florian Wunderlich CLA
Modified: 2022-06-09 10:34 EDT (History)
2 users (show)

See Also:


Attachments
A simple test case to reproduce the problem (2.43 KB, application/x-sdlc)
2010-08-10 09:50 EDT, Florian Wunderlich CLA
no flags Details
proposed fix and test cases (39.33 KB, patch)
2010-09-02 14:05 EDT, Chris Delahunt CLA
no flags Details | Diff
changes to aggregateObjectMapping missed in the first fix (4.12 KB, patch)
2010-09-15 09:26 EDT, Chris Delahunt CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Florian Wunderlich CLA 2010-08-10 09:47:56 EDT
Build Identifier: 20100810 (latest nightly build available on 2010-08-10)

If an entity embeds an embeddable

- that maps a simple property to a column and a many-to-one relationship using the same column,

- and annotates the column mapped from the simple property as not writable,

then EclipseLink will still complain that:

"Multiple writable mappings exist for the field ..."

Reproducible: Always

Steps to Reproduce:
1. Run test case.
Comment 1 Florian Wunderlich CLA 2010-08-10 09:50:19 EDT
Created attachment 176239 [details]
A simple test case to reproduce the problem
Comment 2 Florian Wunderlich CLA 2010-08-10 09:51:19 EDT
The following error messages appear when the test case is run:

Exception [EclipseLink-0] (Eclipse Persistence Services - 2.2.0.v20100810-r8010): org.eclipse.persistence.exceptions.IntegrityException
Descriptor Exceptions: 
---------------------------------------------------------

Exception [EclipseLink-48] (Eclipse Persistence Services - 2.2.0.v20100810-r8010): org.eclipse.persistence.exceptions.DescriptorException
Exception Description: Multiple writable mappings exist for the field [MAINENTITY.col_path].  Only one may be defined as writable, all others must be specified read-only.
Mapping: org.eclipse.persistence.mappings.ManyToOneMapping[reference]
Descriptor: RelationalDescriptor(impl.backend.test.Embedded1 --> [DatabaseTable(MAINENTITY)])

Exception [EclipseLink-48] (Eclipse Persistence Services - 2.2.0.v20100810-r8010): org.eclipse.persistence.exceptions.DescriptorException
Exception Description: Multiple writable mappings exist for the field [MAINENTITY.col_name].  Only one may be defined as writable, all others must be specified read-only.
Mapping: org.eclipse.persistence.mappings.ManyToOneMapping[reference]
Descriptor: RelationalDescriptor(impl.backend.test.Embedded1 --> [DatabaseTable(MAINENTITY)])

Runtime Exceptions: 
---------------------------------------------------------

	at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.initializeDescriptors(DatabaseSessionImpl.java:471)
	at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.initializeDescriptors(DatabaseSessionImpl.java:406)
	at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.postConnectDatasource(DatabaseSessionImpl.java:667)
	at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.loginAndDetectDatasource(DatabaseSessionImpl.java:615)
	at org.eclipse.persistence.internal.jpa.EntityManagerFactoryProvider.login(EntityManagerFactoryProvider.java:228)
	at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:381)
	at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.getServerSession(EntityManagerFactoryImpl.java:157)
	at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:214)
	at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:202)
Comment 3 Florian Wunderlich CLA 2010-08-10 09:59:17 EDT
You will note that the error messages do not appear anymore if just DirectEntity is used - which does exactly the same as MainEntity, but without including the embeddable.

It does not matter which column names are defined in MainEntity at all. I have attached in the test case a version that even uses different column names - the message is always the same, whether the same column names are used as in the embeddable, or different column names, or even different column names between the columns and join columns, as attached.

If Embedded1.referenceId is marked as @Transient, and has all annotations removed, and if the AttributeOverrides in MainEntity are removed, then no error message will appear, the DDL definitions are output correctly, and persist generates a correct INSERT command.
Comment 4 Florian Wunderlich CLA 2010-08-10 10:01:58 EDT
To make it easier to understand this bug, I have extracted the important parts from the test case:


1. The Embeddable:

  @Embedded
  @AttributeOverrides({
    @AttributeOverride(name = "path", 
      column = @Column(name = "col_path", nullable = true,
        insertable = false, updatable = false)),
    @AttributeOverride(name = "name", 
      column = @Column(name = "col_name", nullable = true,
        insertable = false, updatable = false))
  })
  private EmbeddedId1 referenceId;
  
  @ManyToOne(optional = true, fetch = FetchType.LAZY)
  @JoinColumns(value = 
    {
      @JoinColumn(name = "col_path", referencedColumnName = "path", 
        nullable = true),
      @JoinColumn(name = "col_name", referencedColumnName = "name", 
        nullable = true)
    })
  private ReferencedEntity reference;


2. The main entity:

  @Embedded
  @AttributeOverrides({
    @AttributeOverride(name = "referenceId.path", 
      column = @Column(name = "from_path", 
        insertable = false, updatable = false)),
    @AttributeOverride(name = "referenceId.name", 
      column = @Column(name = "from_name", 
        insertable = false, updatable = false))
  })
  @AssociationOverride(name = "reference",
    joinColumns = 
    {
      @JoinColumn(name = "from_path", referencedColumnName = "path",
        nullable = true),
      @JoinColumn(name = "from_name", referencedColumnName = "name",
        nullable = true)
    })
  private Embedded1 from;
Comment 5 Tom Ware CLA 2010-08-24 13:35:05 EDT
Setting target and priority see: http://wiki.eclipse.org/EclipseLink/Development/Bugs/Guidelines for more information on the meanings of these fields.
Comment 6 Chris Delahunt CLA 2010-09-02 14:05:52 EDT
Created attachment 178074 [details]
proposed fix and test cases
Comment 7 Chris Delahunt CLA 2010-09-03 08:12:53 EDT
fix checked into 2.2, revision 8136
- changed foundation so that aggregates store columns as databasefields instead of strings
- added new methods to take DatabaseField parameters.  Old methods still exist to take strings
- signatures on Public methods within AggregateCollectionMapping/EmmbeddableMapping changed to take in maps with databasefield values (instead of strings)
- attribute and assocation overrides will now use column and delimiting info rather than just set the embeddable's field names.
Comment 8 Karen Butzke CLA 2010-09-13 11:31:21 EDT
(In reply to comment #7)
> - attribute and assocation overrides will now use column and delimiting info
> rather than just set the embeddable's field names.

Chris,
I am testing with eclipselink-2.2.0.v20100908-r8149 and I'm am still seeing only the field name taken into account in an attribute override

@Entity
public class Customer {
    @Id protected Integer id;

    @AttributeOverrides({
    @AttributeOverride(name="street",
column=@Column(name="STREET",length=100))})
    @Embedded protected Address address;
}

@Embeddable
public class Address {
	@Column(name="STREET_NAME", length=200, nullable = false)
	protected String street;
}

This is generating a table CUSTOMER with column STREET of length 200 instead of 100.
Comment 9 Karen Butzke CLA 2010-09-13 11:33:00 EDT
Accidentally committed too soon. Here is my example again:

@Entity
public class Customer {
    @Id protected Integer id;

    @AttributeOverrides({
    @AttributeOverride(name="street",
        column=@Column(name="STREET",length=100, nullable = true))})
    @Embedded protected Address address;
}

@Embeddable
public class Address {
    @Column(name="STREET_NAME", length=200, nullable = false)
    protected String street;
}

This is generating a table CUSTOMER with column STREET of length 200 instead of
100. Also nullable is false even though it's been overridden in the AttibuteOverride with true.
Comment 10 Chris Delahunt CLA 2010-09-15 09:26:34 EDT
Created attachment 178927 [details]
changes to aggregateObjectMapping missed in the first fix

This patch adds a test case and changes to AggregateObjectMapping missed in the first checkin.
Comment 11 Chris Delahunt CLA 2010-09-15 10:20:48 EDT
fix checked in revision 8190
Comment 12 Eclipse Webmaster CLA 2022-06-09 10:16:49 EDT
The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink
Comment 13 Eclipse Webmaster CLA 2022-06-09 10:34:22 EDT
The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink