Community
Participate
Working Groups
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.
Created attachment 176239 [details] A simple test case to reproduce the problem
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)
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.
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;
Setting target and priority see: http://wiki.eclipse.org/EclipseLink/Development/Bugs/Guidelines for more information on the meanings of these fields.
Created attachment 178074 [details] proposed fix and test cases
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.
(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.
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.
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.
fix checked in revision 8190
The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink