-
-
Save AlwaysThinkin/cb4913ba47fbd44710db5740a626b9e7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@isTest (seeAllData = true)//We're using SeeAllData = True so we can query records normally not available in Unit Tests. | |
public class SOQLqueriesUpdate { | |
static testMethod void relationshipQueries(){ | |
//Child-to-Parent queries are easy. Simply use the API Name of the lookup field to the parent object | |
//and use dot notation to specify the field on that object you want | |
List<Contact> conAccts = [SELECT FirstName, LastName, Account.Name FROM Contact]; | |
//FIX ME! Use a query with a WHERE filter to only return Contacts from the Account named 'sForce' | |
List<Contact> sForceconAccts = [SELECT FirstName, LastName, Account.Name FROM Contact WHERE Account.Name = 'sForce']; | |
//Here's an unexpected pattern for SOQL queries with Parent-to-Child records: | |
//You would expect that it might be a List<List> pattern so you could call Contacts | |
//with acctsCons[0][0] but instead you must use dot notation to reference the sub-lists | |
List<Account> acctCons = [SELECT Name, (SELECT FirstName, LastName FROM Contacts) FROM Account]; | |
system.debug(acctCons[0].Contacts[0].FirstName); | |
system.debug(acctCons); | |
//FIX ME! Re-create the sForceconAccts List query for the sForce Accounts' Contacts but using Parent-to-Child format instead | |
List<Account> sForceacctCons = [SELECT Name, (SELECT FirstName, LastName FROM Contacts) FROM Account where Name = 'sForce']; | |
// Let's try to query all Accounts with their child Cases in one query call | |
// For each Case that we want to query, we also want to find their Contact Name (another object!) | |
// Notice that this time we are not using 'Case' which is the object name but rather 'Cases' which is the relationship name! | |
List<Account> acctCases = [SELECT id, name, (SELECT id, subject, Contact.Name FROM Cases) FROM Account WHERE name like '%United%' or name like '%Tyco%']; | |
System.debug('Number of accounts: '+ acctCases.size()); | |
System.debug('***Accounts and Cases queried, but only accounts shown on debug****'); | |
System.debug(acctCases); | |
// Let's get the number of cases from the 3rd account | |
System.Debug('But, yes the Cases are queried and we can show those results too if we ask for them'); | |
System.Debug('Number of Cases on 3rd account: '+acctCases[2].Cases.size()); | |
System.debug(acctCases[2].Cases); | |
// Another way to do the same thing is to query all Accounts and all Cases into two separate lists, | |
// but that would require some additional work to get the same result. | |
List<Account> acctNoCases = [SELECT id, name FROM Account WHERE name like '%United%' or name like '%Tyco%' order by name desc]; | |
List<Case> cases = [SELECT id, subject, contact.Name FROM Case]; | |
// Let's get only the cases for the third account queried | |
List<Case> thirdAcctCases = [SELECT id, subject, contact.Name FROM Case WHERE accountid = :acctNoCases[2].id]; | |
System.Debug('Number of cases on the 3rd account queried: '+ thirdAcctCases.size()); | |
//What if we want all the Cases for all the Accounts we queried? | |
//We use the "IN" operator with our bind variable | |
List<Case> allTheCases = [SELECT id, subject, contact.Name FROM Case WHERE accountId IN :acctNoCases]; | |
//FIX ME! Can you write the 3 queries that would get the same results as our "acctCons" query? | |
List<Account> acctNoContacts = [SELECT Name from Account]; | |
List<Contact> contacts = [Select FirstName, LastName from Contact]; | |
List<Contact> allTheContacts = [Select FirstName, LastName from Contact where AccountId IN :acctNoContacts]; | |
} | |
static testMethod void SOQLandCollections(){ | |
//This only works when this test Class is set to SeeAllData=True! | |
List<Account> accts = [SELECT ID FROM Account]; | |
System.debug(accts.size()); | |
System.debug(accts); | |
//System.debug(accts[0].Name);//This won't work because Name was not acquired in the query. | |
accts = [SELECT ID, Name, Phone, BillingState FROM Account]; | |
System.debug(accts.size()); | |
System.debug(accts); | |
System.debug(accts[0].Name); | |
List<Contact> cons = [SELECT Department, MobilePhone, IsDeleted FROM Contact]; | |
System.debug(cons); | |
System.debug('smashing****************************' + cons[0].Id); | |
//Populating a Map from a SOQL Query is also easy, although not as intutive | |
//Note that you have to "cast" the query results (a List) to a Map | |
Map<Id, Account> acctMap1 = new Map<Id, Account>([SELECT ID, Name FROM Account]); | |
System.debug('Account Map: ' + acctMap1); | |
Map<Id, Contact> conMap1 = new Map<Id, Contact>(cons); | |
System.debug(conMap1); | |
Map<Id, Contact> conMap2 = new Map<Id, Contact>([SELECT Id, Department, MobilePhone, IsDeleted FROM Contact]); | |
System.debug(conMap2); | |
//COMMON ROOKIE ERROR | |
//Using Lists to update record instead of Maps | |
List<Account> acctList = [SELECT ID, Name, Industry, Ownership FROM Account]; | |
List<Account> acctListToUpdate = new List<Account>(); | |
//{Some logic here that determines Type must be updated on a record} | |
acctList[0].Type = 'Retailing'; | |
acctListToUpdate.add(acctList[0]); | |
//{Some other logic here that determines Rating must be updated on the same record} | |
acctList[0].Rating = 'Super Hot'; | |
acctListToUpdate.add(acctList[0]); | |
System.debug(acctList[0]); | |
System.debug(acctListToUpdate); | |
/* The update below compiles: you can save this class with it uncommented, but the class | |
* fails when we run the test because we added the same record to the list twice. | |
*/ | |
//update acctListToUpdate;//Fails with "Duplicate id in list" exception. | |
//Let's try the same thing, but using a Map to hold the records to be updated | |
Map<ID, Account> acctMapToUpdate = new Map<Id, Account>(); | |
//We make the same field/values assigment as before on the same record | |
acctList[0].Type = 'Mineral Extraction'; | |
//but now we put the record in a Map instead of a list | |
acctMapToUpdate.put(acctList[0].Id, acctList[0]); | |
//And we do it again for the Rating Field | |
acctList[0].Rating = 'Heavy'; | |
//when we put it a second time, the Map recognizes that the ID already exists, and just | |
//amends the data in the Map with the new information | |
acctMapToUpdate.put(acctList[0].Id, acctList[0]); | |
system.debug(acctMapToUpdate); | |
update acctMapToUpdate.values(); | |
//FIX ME! BIG CHALLENGE!!! | |
//Let's clean up Contacts that lack phone numbers and emails | |
//1. Create a Query to get all Contacts that are missing both a phone number and email address | |
List<Contact> conAccts = [SELECT Id, FirstName, LastName, Name, Phone, CleanStatus, Account.Phone | |
FROM Contact | |
WHERE Phone = null AND Email = Null]; | |
//2. Create an empty collection to hold records we want to update | |
Map<Id, Contact> contactsToUpdateMap = new Map<ID, Contact>(); | |
//3. Set the Contacts' Phone Number to the Account's Phone Number | |
conAccts[0].Phone = conAccts[0].Account.Phone; | |
conAccts[1].Phone = conAccts[1].Account.Phone; | |
//4. Put the records into your update collection | |
//we have to add records to our collection | |
contactsToUpdateMap.put(conAccts[0].Id, conAccts[0]); | |
contactsToUpdateMap.put(conAccts[1].Id, conAccts[1]); | |
//5. Now, since we don't know the email, let's set CleanStatus to 'Skipped' | |
conAccts[0].CleanStatus = 'Skipped'; | |
conAccts[1].CleanStatus = 'Skipped'; | |
//6. Put the records into your update collection | |
//Note that we're adding records again! Be careful! | |
contactsToUpdateMap.put(conAccts[0].Id, conAccts[0]); | |
contactsToUpdateMap.put(conAccts[1].Id, conAccts[1]); | |
//7. Use an "update" call to save the changes and commit them to the database | |
update contactsToUpdateMap.values(); | |
//8. Write a Unit Test to confirm it worked! | |
// Test that there is now a phone number, and that phone number matches the account | |
// Test that the CleanStatus field is "Skipped" | |
List<Contact> updatedContacts = [SELECT CleanStatus, Account.Phone, Phone FROM Contact WHERE Id IN :contactsToUpdateMap.keySet()]; | |
System.AssertEquals('Skipped', updatedContacts[0].CleanStatus); | |
System.AssertEquals('Skipped', updatedContacts[1].CleanStatus); | |
System.assertEquals(updatedContacts[0].Account.Phone, updatedContacts[0].Phone); | |
System.assertEquals(updatedContacts[1].Account.Phone, updatedContacts[1].Phone); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment