Foreign Key constraint violation when persisting a many-to-one class - jpa

I'm getting an error when trying to persist a many to one entity:
Internal Exception: org.postgresql.util.PSQLException: ERROR: insert or update on table "concept" violates foreign key constraint "concept_concept_class_fk"
Detail: Key (concept_class_id)=(Concept) is not present in table "concept_class".
Error Code: 0
Call: INSERT INTO concept (concept_key, description, label, code, concept_class_id) VALUES (?, ?, ?, ?, ?)
bind => [27, description_1, label_1, code_1, Concept]
Query: InsertObjectQuery(com.mirth.results.entities.Concept[conceptKey=27])
at com.sun.ejb.containers.BaseContainer.checkExceptionClientTx(BaseContainer.java:3728)
at com.sun.ejb.containers.BaseContainer.postInvokeTx(BaseContainer.java:3576)
at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1354)
... 101 more
Here is the method that tries to persist it. I've put a comment where the line is:
#Override
public void loadConcept(String metaDataFilePath, String dataFilePath) throws Exception {
try {
ConceptClassMetaData conceptClassMetaData = (ConceptClassMetaData) ModelSerializer.getInstance().fromXML(FileUtils.readFileToString(new File(metaDataFilePath), "UTF8"));
em.executeNativeQuery(conceptClassMetaData.getCreateStatement());
ConceptClassRow conceptClassRow = conceptClassMetaData.getConceptClassRow();
ConceptClass conceptClass = em.findByPrimaryKey(ConceptClass.class, conceptClassRow.getId());
if (conceptClass == null) {
conceptClass = new ConceptClass(conceptClassRow.getId());
}
conceptClass.setLabel(conceptClassRow.getLabel());
conceptClass.setOid(conceptClassRow.getOid());
conceptClass.setDescription(conceptClassRow.getDescription());
conceptClass = em.merge(conceptClass);
DataParser dataParser = new DataParser(conceptClassMetaData, dataFilePath);
for (ConceptModel conceptModel : dataParser.getConceptRows()) {
ConceptFilter<Concept> filter = new ConceptFilter<Concept>(Concept.class);
filter.setCode(conceptModel.getCode());
filter.setConceptClass(conceptClass.getLabel());
List<Concept> concepts = em.findAllByFilter(filter);
Concept concept = new Concept();
if (concepts != null && !concepts.isEmpty()) {
concept = concepts.get(0);
}
concept.setCode(conceptModel.getCode());
concept.setDescription(conceptModel.getDescription());
concept.setLabel(conceptModel.getLabel());
concept.setConceptClass(conceptClass);
concept = em.merge(concept); //THIS LINE CAUSES THE ERROR!
}
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
...
Here are how the two entities are defined:
#Entity
#Table(name = "concept")
#Inheritance(strategy=InheritanceType.JOINED)
#DiscriminatorColumn(name="concept_class_id", discriminatorType=DiscriminatorType.STRING)
public class Concept extends KanaEntity {
#Id
#Basic(optional = false)
#Column(name = "concept_key")
protected Integer conceptKey;
#Basic(optional = false)
#Column(name = "code")
private String code;
#Basic(optional = false)
#Column(name = "label")
private String label;
#Column(name = "description")
private String description;
#JoinColumn(name = "concept_class_id", referencedColumnName = "id")
#ManyToOne
private ConceptClass conceptClass;
...
#Entity
#Table(name = "concept_class")
public class ConceptClass extends KanaEntity {
#Id
#Basic(optional = false)
#Column(name = "id")
private String id;
#Basic(optional = false)
#Column(name = "label")
private String label;
#Column(name = "oid")
private String oid;
#Column(name = "description")
private String description;
....
And also, what's important is the sql that's being generated:
INSERT INTO concept_class (id, oid, description, label) VALUES (?, ?, ?, ?) bind => [LOINC_TEST, 2.16.212.31.231.54, This is a meta data file for LOINC_TEST, loinc_test]
INSERT INTO concept (concept_key, description, label, code, concept_class_id) VALUES (?, ?, ?, ?, ?) bind => [27, description_1, label_1, code_1, Concept]
The reason this is failing is obvious: It's inserting the word Concept for the concept_class_id. It should be inserting the word LOINC_TEST. I can't figure out why it's using this word. I've used the debugger to look at the Concept and the ConceptClass instance and neither of them contain this word. I'm using eclipselink. Does anyone know why this is happening?

You have two conflicting definitions for the column concept_class_id.
The column concept_class_id appears in the #DiscriminatorColumn and #JoinColumn annotations around class Concept. You can't do that. Those two annotations are fighting for control of the column concept_class_id in table concept. #DiscriminatorColumn happens to be winning. That's why the class name, "Concept", appears in the SQL binding where you expect a ConceptClass id.
By the way, #DiscriminatorColumn is only useful when multiple classes share a single table. The #D/C records which class a row represents. If only objects of class Concept are stored in the concept table, then you can remove #DiscriminatorColumn. #D/C is pointless unless you have multiple classes in a table.
To summarize, fixes include:
Alter "name" in Concept's #DiscriminatorColumn annotation
Alter "name" in Concept.conceptClass's #JoinColumn annotation
Remove #DiscriminatorColumn annotation on class Concept
HTH

Related

Cascade delete problem on **custom** unidirectional #OneToMany relationship (JPA eclipselink)

I'm having problem deleting an entity having an Unidirectional #OneToMany custom relationship.
Here the relationship on the "base" entity (relevant columns only):
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "Id", updatable = false)
protected Integer id;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "ObjectId", referencedColumnName = "Id")
protected Collection<Attachment> attachmentsCollection;
Here the relevant columns on the "child" entity:
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "Id", updatable = false)
protected Integer id;
#NotNull
#Basic(optional = false)
#Size(min = 1, max = 64)
#Column(name = "ObjectTable", updatable = false)
protected String objectTable;
#Basic(optional = false)
#Column(name = "ObjectId", updatable = false)
protected Integer objectId;
#NotNull
#Basic(optional = false)
#Lob
#Column(name = "Data")
protected byte[] data;
#NotNull
#Basic(optional = false)
#Column(name = "SizeInBytes")
protected Long sizeInBytes;
#NotNull
#Basic(optional = false)
#Size(min = 1, max = 128)
#Column(name = "Name")
protected String name;
Here explanation on why this is a custom relationship:
The base object is the super class of all entities. It has, additional to its own id, the opportunity to associate any number of attachments via the attachments collection. Since Ids are not unique between tables (entities), it's needed to add an additional column in the child table (the attachment table). This additional column (ObjectTable) identifies the entity-kind owning the attachment. Adding this column to the entity'id (ObjectId) column, the relation is complete:
Suppose record 99 of entity Invoice has 2 attachments (attachment 'Z' and attachment 'Y'):
Table Invoice
-------------
Id ColumnA ColumnB ColumnC...
99 'xyz' '2343' 'zyx'
.
.
Table Attachment
----------------
Id ObjectTable ObjectId Data SizeInBytes Name
43542 'Invoice' 99 11100110 437834 'Z.pdf'
43543 'Invoice' 99 101110 867454 'Y.pdf'
I managed to load the relation with a mapping customizer:
public static final String TABLENAME = "TECAttachment";
public static final String OBJECTIDFIELDNAME = TABLENAME + ".ObjectId";
public static final String OBJECTTABLEFIELDNAME = TABLENAME + ".ObjectTable";
// Customize how records are selecting inside entity's attachments collection: include the entities table name
#Override
public void customize(ClassDescriptor descriptor) {
OneToManyMapping mapping = (OneToManyMapping)descriptor.getMappingForAttributeName(AttachmentEntitySessionCustomizer.ATTACHMENTSCOLLECTIONNAME);
ExpressionBuilder eb = new ExpressionBuilder();
Expression eObjectIdNotNull = eb.getField(AttachmentEntitySessionCustomizer.OBJECTIDFIELDNAME).notNull();
Expression eObjectId = eb.getField(AttachmentEntitySessionCustomizer.OBJECTIDFIELDNAME).equal(eb.getParameter(descriptor.getPrimaryKeyFields().get(0)));
Expression eObjectTable = eb.getField(AttachmentEntitySessionCustomizer.OBJECTTABLEFIELDNAME).equalsIgnoreCase(descriptor.getTableName());
mapping.setSelectionCriteria(eObjectIdNotNull.and(eObjectId.and(eObjectTable)));
}
... but I'm having problems during the delete operation of any entity. For a reason that I still don't understand, JPA is executing an update statement over the Attachment table without taking in consideration the ObjectTable column. Here is what's going on when I delete a record from the table PRHTABidParticipationItem:
Finest: Execute query DeleteObjectQuery(com.tec.uportal.prhta.model.bid.participation.PRHTABidParticipationItem[ id=24 ])
Finest: Execute query DataModifyQuery()
Fine: UPDATE TECAttachment SET ObjectId = ? WHERE (ObjectId = ?)
bind => [null, 24]
Fine: DELETE FROM TECPRHTABidParticipationItem WHERE (Id = ?)
bind => [24]
Finer: end unit of work flush
Finer: resume unit of work
Finer: begin unit of work commit
Finer: commit transaction
My problem is that the UPDATE statement over the table TECAttachment updates all records with the given Id and not only those related to the Entity TECPRHTABidParticipationItem.
I think I must override the sql statements DeleteObjectQuery or DataModifyQuery but don't know how.
Any help will be really appreciated.
I'm working with eclipselink-2.7.4
Thanks in advanace!
After a lot or searching, digging and reading I managed to solve my problem.
Basically:
My attachments collection is an unidirectional custom #OneToMany relationship.
I was in the correct path trying to achieve my goal with a collection customizer (a class associated to my collection via annotation and implementing the DescriptorCustomizer interface).
My customizer not only needs to customize the way the "child" records are selected, also it's needed to customize what to do when the parent record is deleted.
The way to do this is to override the default removeAllTargetsQuery property providing a new custom query through the method mapping.setCustomRemoveAllTargetsQuery(DataModifyQuery).
The most difficult part was to understand how the underlying eclipselink implementation sends parameters (which, order, type, etc.) to the custom DataModifyQuery. I had to download the source code of EclipseLink's JPA implementation and figure out how things are done...
Finally, everything is working good and ok thanks to the following simple DescriptorCustomizer:
package com.tec.uportal.model.customizer;
import org.eclipse.persistence.config.DescriptorCustomizer;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.expressions.Expression;
import org.eclipse.persistence.expressions.ExpressionBuilder;
import org.eclipse.persistence.internal.helper.DatabaseField;
import org.eclipse.persistence.mappings.OneToManyMapping;
import org.eclipse.persistence.queries.DataModifyQuery;
/**
*
* #author MarcB
*/
public class AttachmenstCollectionAttributeCustomizer implements DescriptorCustomizer {
public static final String ATTACHMENTS__COLLECTION_NAME = "attachmentsCollection";
public static final String ATTACHMENTS_TABLE_OBJECT_TABLE__FIELD_NAME = "ObjectTable";
// Customize attachments collection mapping
#Override
public void customize(ClassDescriptor descriptor) {
// Customize how records are selected inside parent entity's attachments collection: include in the WHERE clause the column ObjectTable
OneToManyMapping mapping = (OneToManyMapping)descriptor.getMappingForAttributeName(ATTACHMENTS__COLLECTION_NAME);
ExpressionBuilder eb = new ExpressionBuilder();
Expression eObjectId = eb.getField(mapping.getTargetForeignKeyFields().get(0).getQualifiedName()).equal(eb.getParameter(descriptor.getPrimaryKeyFields().get(0)));
Expression eObjectTable = eb.getField(mapping.getTargetForeignKeyFields().get(0).getTable().getQualifiedName() + "." + ATTACHMENTS_TABLE_OBJECT_TABLE__FIELD_NAME).equalsIgnoreCase(descriptor.getTable(descriptor.getTableName()).getQualifiedName());
mapping.setSelectionCriteria(eObjectId.and(eObjectTable));
// Customize what must be done (delete childs) when parent entity is deleted
DataModifyQuery dmf = new DataModifyQuery("DELETE " + mapping.getTargetForeignKeyFields().get(0).getTable().getQualifiedName() + " WHERE " + mapping.getTargetForeignKeyFields().get(0).getName() + " = #" + mapping.getTargetForeignKeyFields().get(0).getName() + " AND " + ATTACHMENTS_TABLE_OBJECT_TABLE__FIELD_NAME + " = '" + descriptor.getTableName() + "'");
mapping.setCustomRemoveAllTargetsQuery(dmf);
}
}

How to keep data in sync with JPA across entities in session cache?

Im trying to figure out how to keep data in sync in the session cache. I have the following example:
#Table (name = "language")
#Entity
public class Language
{
#Id
#Column (name = "key", unique = true, nullable = false)
private String key;
#Column (name = "name", unique = true, nullable = false)
private String name;
#OneToMany (mappedBy = "language", cascade = { CascadeType.DETACH, CascadeType.REFRESH, CascadeType.REMOVE })
private Set<Translation> translations;
}
#Table (name = "translation")
#Entity
public class Translation
{
#Id
#GeneratedValue (strategy = GenerationType.SEQUENCE)
private Long id;
#ManyToOne(optional = false)
private Language language;
#ManyToOne (optional = false)
#JoinColumn(referencedColumnName = "key")
private TranslatableEntity translatable;
#Column(name = "value")
private String value;
}
#Table (name = "translatable")
#Entity
public class Translatable
{
#Id
#GeneratedValue (strategy = GenerationType.SEQUENCE)
private Long id;
#NotNull
#Size (max = 255)
#Column (name = "key", unique = true, nullable = false)
private String key;
#OneToMany (mappedBy = "translatable", cascade = { CascadeType.DETACH, CascadeType.REFRESH, CascadeType.REMOVE, CascadeType.PERSIST })
#MapKey (name = "language")
private Map<Language, Translation> translations;
}
So basically I do:
// Print current translations for en language
Language language = languageRepository.getOne("en");
printTranslations(language);
// Add new translatable object with translation for english language
Translatable translatable = new Translatable();
translatable.addTranslation("en", "...")
translatableRepository.saveAndFlush(translatable)
// Again print translations for en language
// This still prints outdated information
language = languageRepository.getOne("en");
printTranslations(language);
So my question is how to keep data consistent.
When inserting/removing a new translatable with some translations the translation list in Language instances are not updated in the session cache.
I could not find any satisfactory answer to this. This one came closest: Keeping entity relationship in sync when deleting child in JPA.
Thanks
JPA doesn't maintain the two sides of a bidirectional relationship for you.
And the purpose of the first level cache is that within a transaction entities get loaded only once.
This gives you two options to solve the problem:
maintain both sides of the relationship yourself, for example by implementing the Translatable.add method so that it updates Language.translations and Translation.language
force a reload of language by either evicting it or by closing the session (i.e. the transaction) before calling languageRepository.getOne("en")

Mapping from table to entity on non-unique column

I have a table definition which looks like this. I do not have the luxury to change the column defn.
table definition
Table FOO{
F_ID NUMBER, -- PK
CODE VARCHAR2(10), -- NON UNIQUE
F_NAME VARCHAR2(10)
}
Table BAR{
B_ID NUMBER, -- PK
CODE VARCHAR2(10), --NON UNIQUE
B_NAME VARCHAR2(10)
}
I need to map this to two entities.
Please note that the relationship is one to many. that is, one Foo can have multiple Bars from an entity point of view.
However,
the same code, which is the common column is non unique in both tables, and can have multiple values in both tables.
I know this can be solved using a join afterwards, but the Bar information is required for every Foo object that gets loaded up.
Is there a way to map this naturally using ORM using a join on the common column code?
#Entity
#Table(name = "FOO")
class Foo{
#Id
#Column(name = "F_ID", nullable = false)
private Long id;
#Column(name = "F_NAME")
private String fName;
#Column(name = "CODE", nullable = false)
private String code;
//What should be the join condition?
private List<Bar> bars;
}
#Entity
#Table(name = "BAR")
class Foo{
#Id
#Column(name = "B_ID", nullable = false)
private Long id;
#Column(name = "B_NAME")
private String bName;
//Is this required?
//private String code;
}

Hibernate Filter being ignored

My application uses Hibernate 5.02 and Wildfly 10 with a PostgreSQL 9.5 database. I'm trying to enable a filter on a #OneToMany collection held within an entity that is constructed via a NamedQuery. Unfortunately, it seems as if the filter is just ignored. Here are the different components, redacted for ease of reading.
#NamedNativeQueries({
#NamedNativeQuery(
name = "getAnalystProcess",
query = "SELECT * FROM analysis.analystprocess WHERE id = :processId",
resultClass = AnalystProcessEntity.class
)})
#FilterDef(
name = "analystProcessUnanalyzedMsgsFilter",
parameters = { #ParamDef(name = "processIds", type = "integer"), #ParamDef(name = "analystIds", type = "integer") })
#Filter(name = "analystProcessUnanalyzedMsgsFilter", condition = "analystprocess_id IN (:processIds) AND id NOT IN (SELECT msg_id FROM analysis.analyzedmsg WHERE analyst_id IN (:analystIds) AND analystprocess_id IN (:processIds)) ORDER BY process_msg_id")
#Entity
#Table(name = "analystprocess", schema = "analyst")
public class AnalystProcessEntity implements JPAEntity {
public static final String GET_PROCESS = "getAnalystProcess";
public static final String MSG_FILTER = "analystProcessUnanalyzedMsgsFilter";
public static final String MSG_FILTER_PROC_ID_PARAM = "processIds";
public static final String MSG_FILTER_ANALYST_ID_PARAM = "analystIds";
private static final long serialVersionUID = 1L;
...
#OneToMany(fetch = FetchType.LAZY, orphanRemoval = true, mappedBy = "process")
#OrderColumn(name = "process_msg_id")
#LazyCollection(LazyCollectionOption.EXTRA)
private List<MsgEntity> msgList;
#Entity
#Table(name = "msg", schema = "analyst")
public class MsgEntity implements JPAEntity {
...
#ManyToOne(cascade = CascadeType.ALL, optional = false)
#JoinColumn(name = "analystprocess_id", referencedColumnName = "id")
private AnalystProcessEntity process;
#Column(name = "process_msg_id")
private Integer processMsgId;
private void buildAnalystProcess() {
LOG.info("Building AnalystProcessEntity");
analystUser.getJdbcSession().enableFilter(AnalystProcessEntity.MSG_FILTER)
.setParameter(AnalystProcessEntity.MSG_FILTER_PROC_ID_PARAM, analystProcessId)
.setParameter(AnalystProcessEntity.MSG_FILTER_ANALYST_ID_PARAM, analystUser.getId());
Query query = analystUser.getJdbcSession().getNamedQuery(AnalystProcessEntity.GET_PROCESS)
.setParameter("processId", analystProcessId);
// Query query = analystUser.getJdbcSession().createNativeQuery("SELECT * FROM analysis.analystprocess WHERE id = :processId")
// .setParameter("processId", analystProcessId)
// .addEntity(AnalystProcessEntity.class);
analystProcess = (AnalystProcessEntity) query.getSingleResult();
CREATE TABLE analysis.analystprocess (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL UNIQUE,
description TEXT,
created_date TIMESTAMP NOT NULL DEFAULT now(),
...
);
CREATE TABLE analysis.msg (
id SERIAL PRIMARY KEY,
analystprocess_id INTEGER NOT NULL REFERENCES analysis.analystprocess(id) ON DELETE CASCADE ON UPDATE CASCADE,
process_msg_id INTEGER NOT NULL,
constraint tbl_statusid_analystprocessid unique(status_id, analystprocess_id)
);
As seen above, I have also tried the filter on constructing the AnalystProcessEntity class via createNativeQuery instead of getNamedQuery and no luck.
I also added a defaultCondition with hardcoded values into the #FilterDef just to see if it would execute the default condition and it still didn't.
I've tried the #Filter above the entity definition as well as above the class definition. I even came across a blog post which made it sound like the condition references entity fields (variable names) and not table fields (column names). Trying to stick to Java naming conventions in the Entity and Postgres naming conventions in the table, so I tried switching the references in the condition and to no avail.
I have sql logging turned on in Hibernate and the condition doesn't show up anywhere, as if it's just simply being ignored.
Any help would be greatly appreciated!
So, the problem was that I had the #FilterDef applied to the wrong class. It was my presumption that because I was constructing the AnalystProcessEntity which holds the MsgEntity collection (which I am trying to filter), that the #FilterDef would be applied to the AnalystProcessEntity class. Instead, it needs to be applied to the entity that it's actually filtering (hindsight being 20/20, that's pretty obvious).
Also, the actual condition needed to be modified to use complete references within the sub-select query.
I hope this helps someone at some point...
#NamedNativeQueries({
#NamedNativeQuery(
name = "getAnalystProcess",
query = "SELECT * FROM analysis.analystprocess WHERE id = :processId",
resultClass = AnalystProcessEntity.class
)})
#Filter(name = "analystProcessUnanalyzedMsgsFilter", condition = "id NOT IN (SELECT amsg.msg_id FROM analysis.analyzedmsg amsg WHERE amsg.analyst_id IN (:analystIds) AND amsg.analystprocess_id IN (:processIds))")
#Entity
#Table(name = "analystprocess", schema = "analyst")
public class AnalystProcessEntity implements JPAEntity {
public static final String GET_PROCESS = "getAnalystProcess";
public static final String MSG_FILTER = "analystProcessUnanalyzedMsgsFilter";
public static final String MSG_FILTER_PROC_ID_PARAM = "processIds";
public static final String MSG_FILTER_ANALYST_ID_PARAM = "analystIds";
private static final long serialVersionUID = 1L;
...
#OneToMany(fetch = FetchType.LAZY, orphanRemoval = true, mappedBy = "process")
#OrderColumn(name = "process_msg_id")
#LazyCollection(LazyCollectionOption.EXTRA)
private List<MsgEntity> msgList;
#FilterDef(
name = "analystProcessUnanalyzedMsgsFilter",
parameters = { #ParamDef(name = "processIds", type = "integer"), #ParamDef(name = "analystIds", type = "integer") })
#Entity
#Table(name = "msg", schema = "analyst")
public class MsgEntity implements JPAEntity {
...
#ManyToOne(cascade = CascadeType.ALL, optional = false)
#JoinColumn(name = "analystprocess_id", referencedColumnName = "id")
private AnalystProcessEntity process;
#Column(name = "process_msg_id")
private Integer processMsgId;
Additionally, I ran into another problem with null's appearing in the collection, despite the fact that I am using an #OrderColumn, which I thought fixed that issue. It seems that with the use of the #Filter, null's are inserted in place of what ended up being filtered OUT (excluded).

Unneeded column added trying to set up OneToMany relationship

I'm trying to set up a OneToMany relationship between an author and his posts with author as the foreign key and username as primary key, using Java EE 6 and toplink+eclipselink as persistence provider.
Here is what i have:
Annotations in class User
#Id
#NotNull(message = "Please enter username")
#Size(min = 8, max = 40)
#Column(unique=true, nullable=false)
private String username;
...
private Collection<BlogEntry> blg = new ArrayList<BlogEntry>();
#OneToMany(cascade = {CascadeType.ALL}, mappedBy="user")
public Collection<BlogEntry> getBlg() {
return blg;
}
Annotations in class BlogEntry
#NotNull
#Size(min = 8, max = 40)
private String author;
...
private User user;
#ManyToOne()
public User getUser() {
return user;
}
The problem is that a new column(USER_USERNAME) is added when inserting values into BlogEntry Table, which of course shows an error of the field not existing in BlogEntry:
INSERT INTO BLOGENTRY (ID, CONTENT, AUTHOR, TITLE, CREATED, USER_USERNAME) VALUES (?, ?, ?, ?, ?, ?)
bind => [301, xxxxxxxx, xxxxxxxx, xxxxxxxx, 2011-06-07 12:49:07.014, null]
I would be very glad to learn why such a column is added or what to fix to get a simple OneToMany relationship using username and author fields. I searched and tried many tutorials but seems i'm missing something.
If you want to use an existing AUTHOR column as a foreign key, you need to map many-to-one relationship to that column as follows:
#ManyToOne()
#JoinColumn(name = 'author')
private User user;
Note that in typical case you can remove a separate author field from the class, since now it can be obtained as user.getUsername(). If you need both fields in the class, you need to mark one of them as read-only with insertable = false, updateable = false, because only one read-write field can be mapped to a particular column.