Showing posts with label sObject. Show all posts
Showing posts with label sObject. Show all posts

Tuesday, January 14, 2014

Exotic SF objects with properties.

This is list of exotic SF objects and their properties. List will be growing, as I will add new after "playing".

API Name
Prefix
Trigger
DML
SOQL
REST
Describe
CurrencyType
01L
No
No DML [1]
+
+
DatedConversionRate
04w
No
No DML [1]
+
POST / DELETE
+
Application
06P
No
No DML
No SOQL
No describe
AppManifes
0Ci
No
No DML
No SOQL
No describe
AccountTerritoryAssignmentRule
-
No
No DML [1]
No SOQL
No describe


References:

1. sObjects That Don’t Support DML Operations;

Enjoy.

Sunday, October 28, 2012

Work with Salesforce To Salesforce (S2S) in APEX.

In SF there are two objects responsible for S2S connection: PartnerNetworkConnection - keeps all information about current connection and PartnerNetworkRecordConnection - holds information about record that was forwarded. I will not write here how to create S2S connection, there is a lot of information about in internet. We will talk about forwarding objects that are already published and subscribed in both orgs. We can forward objects in two ways: manualy in page or in code. Below is sample of class to do this in code:
public class S2SService {
    public static final String CONNTECTION_STATUS_ACCEPTED = 'Accepted';
// Method return Id of current connection. 
    public static Id getConnectionId( String connectionName ) {
        return [SELECT Id 
            FROM PartnerNetworkConnection 
            WHERE connectionStatus = : CONNTECTION_STATUS_ACCEPTED 
                      AND connectionName = : connectionName 
                LIMIT 1].Id; 
    } 
/* 
@param: objectList - list of objects you want to forward; 
@param: parentRecordIdMap - Map<Record Id; Parent Id> map of Parent records;
@param: relatedRecordsMap - Map<Record Id; String with related records String>
                            map with objects API names for whom forwarding record
                            is parent and you want to forward them too; 
@param: connectionName - name of connection you want to use; 
*/ 
    public static void sendToPartnerOrg( List<sObject> objectList,
                                         Map<Id,Id> parentRecordIdMap, 
                                         Map<Id,String> relatedRecordsMap,
                                         String connectionName ){ 
        if ( objectList != null && !objectList.isEmpty() ){ 
// First thing we need to have connection name
            Id connectionId = getConnectionId( connectionName ); 
// Creating list of PartnerNetworkRecordConnection that will be inserted
        List<PartnerNetworkRecordConnection> objectConnections 
            =  new  List<PartnerNetworkRecordConnection>(); 
// Going throught list of recordth we want to share            
        for ( sObject obj: objectList ) 
// Adding new PartnerNetworkRecordConnection to list
            objectConnections.add(  
                new PartnerNetworkRecordConnection( 
// ConnectionId - setting our PartnerNetworkConnection Id
                    ConnectionId = connectionId, 
// LocalRecordId - Id of record we want to forward
                    LocalRecordId = obj.Id, 
// SendClosedTasks and SendOpenTasks false because we do not wont to forward tham too
                    SendClosedTasks = false,
                    SendOpenTasks = false,
                    SendEmails = true, 
// ParentRecordId - parent of forwarding record
                    ParentRecordId = parentRecordIdMap != null ?
                                     parentRecordIdMap.get( obj.Id ): 
                                     null,
// RelatedRecords - child objects you what to forward too
                    RelatedRecords = relatedRecordsMap != null ?
                                     relatedRecordsMap.get( obj.Id ): 
                                     null )
            ); 
// Upserting of PartnerNetworkRecordConnection list with linking error to the object
// we are forwarding 
        if ( !objectConnections.isEmpty() ) {
            try{ 
                database.upsert( objectConnections ); 
            }catch( DMLException dmlEx ){ 
                for ( Integer i = 0; i < dmlEx.getNumDml(); i++ )
                    if( dmlEx.getDmlStatusCode( i ) == 'INVALID_PARTNER_NETWORK_STATUS' ) 
                        for( PartnerNetworkRecordConnection connectionItem: objectConnections ) 
                            if( dmlEx.getDmlId( i ) == connectionItem.Id ) 
                                for( sObject obj : objectList ) 
                                    if( connectionItem.LocalRecordId == obj.Id ) 
                                        obj.addError( 'Incorrect partner network status.' );
                } 
            } 
        }  
    } 
}
Note: if there will be an error, in upserting one the record, all bunch will not be forwarded.

Also we do not need to forget about SF Governors and Limits. Because if we have triggers and some logic on forwarded records, in partner org, we can hit them. In this case we will not get error on Connection history, but all upserted PartnerNetworkRecordConnections will have status "Pending (sent)" and will not be forwarded.

To be able to forward records again we need to change status of PartnerNetworkRecordConnection from "Pending (sent)" to "Inactive". To do this we need to delete PartnerNetworkRecordConnection, but it will not be deleted, it will just change status to "Pending (sent)". After this we can insert tham again. If there will not be any errors, status will change to "Active (sent)" or "Connected" in several seconds. So if we need to change something in PartnerNetworkRecordConnection, we need to delete it and insert/upsert it again. This is strange way to work with, but it is only way.

One more thing. When we are forwarding records and filling in field ParentRecordId, we need to be sure that parent record is already forwarded, in other case we will have an error.

Useful links:


Enjoy.

Apex, check object by Id.

Some times we need to know if Id matches the object we need. This method returns true, if matches:
public static Boolean isIdsObjectTypeEqualToStringObjectType( String objectIdString,
                                                              String objectTypeNameString ){
    Map<String, Schema.SObjectType> globalDescrideMap = Schema.getGlobalDescribe();    
    Boolean isEqual = false;
            
    Map<String,String> keyPrefixMap = new Map<String,String>{};

    for( String objectItem : globalDescrideMap.keySet() ){
       Schema.DescribeSObjectResult objectDescribe =  globalDescrideMap.get(objectItem).getDescribe();
       keyPrefixMap.put( objectDescribe.getKeyPrefix(), objectDescribe.getName() );
    }
    
    if( keyPrefixMap.get( objectIdString.subString( 0, 3 ) ) == objectTypeNameString ) isEqual = true;
    
    return isEqual;
}
Recommend to to move initialization of globalDescrideMap to top of class. And of course test:
@isTest( seeAllData = false ) private static void testIsIdsObjectTypeEqualToStringObjectType(){
    Integer NUMBER_TO_INSERT = 5;
    List<Account> testAccountList = new List<Account>();
    List<Boolean> testEqualsList = new List<Boolean>();
    List<Boolean> testNotEqualsList = new List<Boolean>();
    String accountObjectType = Account.getsObjectType().getDescribe().getName();
    
    for( Integer i = 0; NUMBER_TO_INSERT > i; i++ )
        testAccountList.add( TestingUtils.createTestAccount( null ) );
        
    insert testAccountList;
    
    Test.startTest();
        for( Account accountItem : testAccountList )
            testEqualsList.add( BluewolfDevUtils.isIdsObjectTypeEqualToStringObjectType( ( String )accountItem.Id, accountObjectType ) );
        
        for( Account accountItem : testAccountList )
            testNotEqualsList.add( BluewolfDevUtils.isIdsObjectTypeEqualToStringObjectType( ( String )accountItem.Id, 'Account__c' ) );
    Test.stopTest();
    
    for( Boolean testEqualsItem : testEqualsList )
        System.assertEquals( true, testEqualsItem );
    
    for( Boolean testNotEqualsItem : testNotEqualsList )
        System.assertEquals( false, testNotEqualsItem );
}
Enjoy.

UTD: New method.

Salesforce: Unified object creator.

Everytime when we write test classes, we need to a create a big number of data to apply them to the methods that we are testing. We create a lot of methods leading to the creation of these or those objects. I have created the method leading to the creation of any type objects we need:
public with sharing class Utilities {
    /*
        Method for creating any Object
    */
    
    public static List<sObject> createObject(Integer numberToCreate, 
                                             Boolean doInsert, 
                                             Schema.SObjectType objectType, 
                                             Map<String, String> fieldsMap){    
        List<sObject> objectsList = new List<sObject>();
        List<String> objectFields = new List<String>();
        List<String> fieldsList = new List<String>();
        
        objectFields.addAll(objectType.getDescribe().fields.getMap().keySet());
        fieldsList.addAll(fieldsMap.keySet());
        
        if(numberToCreate > 0){
            for( Integer countOfObjects = 0; countOfObjects < numberToCreate; countOfObjects++ ){
                SObject currentObject = objectType.newSObject();
                
                for(String fieldFromList : fieldsList){
                    for(String fieldFromObject : objectFields){
                        if(fieldFromObject == fieldFromList){
                            currentObject.put(fieldFromList , fieldsMap.get(fieldFromList));
                        }
                    }
                }    

                objectsList.add(currentObject);
            }

            if ( doInsert ) insert objectsList;
        }
        
        return objectsList;
    }
}
Also I have added test class for it:
@isTest
private class TestUtilities {
    private static final Integer TEST_RECORD_COUNT = 10;
    
    static Map<String, String> fieldsMap;    
    static Schema.SObjectType objectType;
    static List<String> objectFields = new List<String>();
    static String query;
        
    private static void setup(){
        objectType = Account.getsObjectType();
        objectFields.addAll(objectType.getDescribe().fields.getMap().keySet());
        fieldsMap = new Map<String, String>{'Name' => 'Test',            //Fill in fields
                                            'BillingCountry' => 'Usa',    //IMPORTANT You need to fill in requaired fields
                                            'AccountSource' => 'Web'};
    }
    
    private static testmethod void testCreateObject(){
        List<sObject> testCreatedObjects;
        List<sObject> objectsFromDB;
        List<String> fieldsFromBD = new List<String>();
        
        setup();
        
        Test.startTest();
            testCreatedObjects = Utilities.createObject(TEST_RECORD_COUNT,
                                                           true,
                                                           objectType,
                                                           fieldsMap);
        Test.stopTest();
        
        query = 'SELECT Id';
        
        fieldsFromBD.addAll(fieldsMap.keySet());
        
        for(String fieldDB : fieldsFromBD){
            for(String fieldObject : objectFields){
                if(fieldDB == fieldObject){
                    query += ', ' + fieldDB;
                }
            }
        }
        
        query += ' FROM ' + objectType + ' WHERE Id IN : ' + 'testCreatedObjects' +  ' ';
        
        objectsFromDB = Database.query(query);        
        
        System.assertEquals( TEST_RECORD_COUNT , objectsFromDB.size() );
    }
}
You can also add compare of every field it test.

Enjoy.