diff --git a/src/main/java/com/salesforce/dataloader/action/visitor/DAOLoadVisitor.java b/src/main/java/com/salesforce/dataloader/action/visitor/DAOLoadVisitor.java index df82d863..fb71724d 100644 --- a/src/main/java/com/salesforce/dataloader/action/visitor/DAOLoadVisitor.java +++ b/src/main/java/com/salesforce/dataloader/action/visitor/DAOLoadVisitor.java @@ -71,8 +71,8 @@ public abstract class DAOLoadVisitor extends AbstractVisitor implements DAORowVi protected final List dynaArray; private HashMap rowConversionFailureMap; - protected final BasicDynaClass dynaClass; - protected final DynaProperty[] dynaProps; + protected BasicDynaClass dynaClass = null; + protected DynaProperty[] dynaProps = null; private final int batchSize; protected List daoRowList = new ArrayList(); @@ -95,9 +95,6 @@ protected DAOLoadVisitor(Controller controller, ILoaderProgress monitor, DataWri SforceDynaBean.registerConverters(getConfig()); - dynaProps = SforceDynaBean.createDynaProps(controller.getFieldTypes(), controller); - dynaClass = SforceDynaBean.getDynaBeanInstance(dynaProps); - this.batchSize = getConfig().getLoadBatchSize(); rowConversionFailureMap = new HashMap(); String newRichTextRegex = getConfig().getString(Config.RICH_TEXT_FIELD_REGEX); @@ -131,6 +128,16 @@ public boolean visit(Row row) throws OperationException, DataAccessObjectExcepti } // the result are sforce fields mapped to data Row sforceDataRow = getMapper().mapData(row); + + // Make sure to initialize dynaClass only after mapping a row. + // This is to make sure that all polymorphic field mappings specified + // in the mapping file are mapped to parent object. + if (dynaProps == null) { + dynaProps = SforceDynaBean.createDynaProps(controller.getFieldTypes(), controller); + } + if (dynaClass == null) { + dynaClass = SforceDynaBean.getDynaBeanInstance(dynaProps); + } try { convertBulkAPINulls(sforceDataRow); DynaBean dynaBean = SforceDynaBean.convertToDynaBean(dynaClass, sforceDataRow); diff --git a/src/main/java/com/salesforce/dataloader/client/PartnerClient.java b/src/main/java/com/salesforce/dataloader/client/PartnerClient.java index 087d5fdc..c1301d51 100644 --- a/src/main/java/com/salesforce/dataloader/client/PartnerClient.java +++ b/src/main/java/com/salesforce/dataloader/client/PartnerClient.java @@ -36,6 +36,7 @@ import com.salesforce.dataloader.config.Config; import com.salesforce.dataloader.config.Messages; import com.salesforce.dataloader.controller.Controller; +import com.salesforce.dataloader.dyna.RelationshipField; import com.salesforce.dataloader.dyna.SforceDynaBean; import com.salesforce.dataloader.exception.ParameterLoadException; import com.salesforce.dataloader.exception.PasswordExpiredException; @@ -938,7 +939,6 @@ private boolean checkConnectionException(ConnectionException ex, String operatio private final Map fieldsByName = new HashMap(); public Field getField(String sObjectFieldName) { - sObjectFieldName = sObjectFieldName.toLowerCase(); Field field = this.fieldsByName.get(sObjectFieldName); if (field == null) { field = lookupField(sObjectFieldName); @@ -948,10 +948,29 @@ public Field getField(String sObjectFieldName) { } private Field lookupField(String sObjectFieldName) { + boolean isRelationshipField = RelationshipField.isRelationshipFieldMapping(sObjectFieldName); + RelationshipField relField = new RelationshipField(sObjectFieldName, true); // look for field on target object for (Field f : getFieldTypes().getFields()) { - if (sObjectFieldName.equals(f.getName().toLowerCase()) || sObjectFieldName.equals(f.getLabel().toLowerCase())) + if (sObjectFieldName.equalsIgnoreCase(f.getName()) || sObjectFieldName.equalsIgnoreCase(f.getLabel())) { return f; + } + if (isRelationshipField + && relField != null + && relField.getRelationshipName().equalsIgnoreCase(f.getRelationshipName())) { + Field parentField = this.referenceEntitiesDescribesMap.getParentField(sObjectFieldName); + if (parentField != null) { + return parentField; + } + // need to add the relationship mapping to referenceEntitiesDescribesMap + try { + processParentObjectForLookupReferences(relField.getParentObjectName(), f, 0, 1); + } catch (ConnectionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return this.referenceEntitiesDescribesMap.getParentField(sObjectFieldName); + } } return this.referenceEntitiesDescribesMap.getParentField(sObjectFieldName); } diff --git a/src/main/java/com/salesforce/dataloader/dyna/SforceDynaBean.java b/src/main/java/com/salesforce/dataloader/dyna/SforceDynaBean.java index 88042846..aaa2c0e8 100644 --- a/src/main/java/com/salesforce/dataloader/dyna/SforceDynaBean.java +++ b/src/main/java/com/salesforce/dataloader/dyna/SforceDynaBean.java @@ -85,9 +85,8 @@ static public DynaProperty[] createDynaProps(DescribeSObjectResult describer, Co // NOTE: currently only fields with one reference are supported on the server FieldType fieldType = field.getType(); String relationshipName = field.getRelationshipName(); - if (fieldType == FieldType.reference && field.getReferenceTo().length <= DescribeRefObject.MAX_PARENT_OBJECTS_IN_REFERENCING_FIELD && + if (fieldType == FieldType.reference && relationshipName != null && relationshipName.length() > 0) { - for (String parentName : field.getReferenceTo()) { RelationshipField relField = new RelationshipField(parentName, relationshipName); DescribeRefObject parent = controller.getReferenceDescribes().getParentSObject(relField.toFormattedRelationshipString()); diff --git a/src/test/java/com/salesforce/dataloader/process/CsvProcessAttachmentTest.java b/src/test/java/com/salesforce/dataloader/process/CsvProcessAttachmentTest.java index 0378ca48..3eae56bd 100644 --- a/src/test/java/com/salesforce/dataloader/process/CsvProcessAttachmentTest.java +++ b/src/test/java/com/salesforce/dataloader/process/CsvProcessAttachmentTest.java @@ -32,14 +32,17 @@ import com.salesforce.dataloader.action.progress.ILoaderProgress; import com.salesforce.dataloader.config.Config; import com.salesforce.dataloader.controller.Controller; +import com.salesforce.dataloader.dyna.RelationshipField; import com.salesforce.dataloader.exception.DataAccessObjectException; import com.salesforce.dataloader.exception.ProcessInitializationException; import com.salesforce.dataloader.exception.UnsupportedOperationException; import com.salesforce.dataloader.model.Row; import com.sforce.soap.partner.QueryResult; +import com.sforce.soap.partner.SaveResult; import com.sforce.soap.partner.sobject.SObject; import com.sforce.ws.ConnectionException; import org.junit.Assert; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -98,6 +101,31 @@ public void testCreateAttachment() throws ProcessInitializationException, DataAc runProcess(argMap, 1); } } + + @Test + public void testPolymorphicRelationshipInAttachment() throws ProcessInitializationException, DataAccessObjectException, ConnectionException { + // convert the template using the parent account id + Map configMap = getTestConfig(OperationInfo.insert, false); + + // this feature does not work when bulk api is enabled but the zip content type is not + final boolean bulkApi = isBulkAPIEnabled(configMap); + final boolean zipContent = isSettingEnabled(configMap, Config.BULK_API_ZIP_CONTENT); + if (bulkApi && !zipContent) { + return; + } + AccountGenerator acctGen = new AccountGenerator(); + SObject[] parentAccts = new SObject[1]; + parentAccts[0] = acctGen.getObject(0, false); + + // value of Oracle_id__c = 1-000000 + SaveResult[] results = getBinding().create(parentAccts); + parentAccts[0].addField("id", results[0]); + + configMap.put(Config.ENTITY, "Attachment"); + RelationshipField parentRel = new RelationshipField("Account", "Parent"); + parentRel.setParentFieldName(DEFAULT_ACCOUNT_EXT_ID_FIELD); + runProcess(configMap, 1); + } /** * Verify that multiple binary files can be correctly zipped up and inserted into a record. diff --git a/src/test/resources/testfiles/data/polymorphicRelationshipInAttachment.csv b/src/test/resources/testfiles/data/polymorphicRelationshipInAttachment.csv new file mode 100644 index 00000000..8635f057 --- /dev/null +++ b/src/test/resources/testfiles/data/polymorphicRelationshipInAttachment.csv @@ -0,0 +1,2 @@ +Name,Body,Parent:Account-Oracle_Id__c +TestAttachment_01.txt,"target/test-classes/testfiles/data/attachment.txt","1-000000" \ No newline at end of file diff --git a/src/test/resources/testfiles/data/polymorphicRelationshipInAttachmentMap.sdl b/src/test/resources/testfiles/data/polymorphicRelationshipInAttachmentMap.sdl new file mode 100644 index 00000000..75245760 --- /dev/null +++ b/src/test/resources/testfiles/data/polymorphicRelationshipInAttachmentMap.sdl @@ -0,0 +1,5 @@ +# extract account mapping values for query from salesforce (left) and update to csv file (right) +# salesforceFieldName=csvFieldName +Name=Name +Body=Body +Parent\:Account-Oracle_Id__c=Parent\:Account-Oracle_Id__c \ No newline at end of file