function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
SeraphSeraph 

N>Trigger to Check 2 Different Fields from 2 Different Custom Objects

I have this visualforce page to show/explain my problem better
DisplayTable.page
I need a trigger (after insert,after update I think) to check if any record (from Item__c :Type__c) uses any of the values (from Gadget__c : Name) and if so it puts a value (at Gadget__c : Status) either Used or Unused like shown on the screenshot. It also changes if the value (from Item__c :Type__c) is changed which I think why the trigger must also be after update.

here is my working code:

visualforce page
<apex:page sidebar="false" controller="DisplayStatus">
   <apex:stylesheet value="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"/>
   <apex:includeScript value="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js" />

   <div class="row">
       <div class="col-xs-6">
          <apex:pageBlock title="Gadget (Gadget__c)">
             <apex:pageBlockTable value="{!gadgetlist}" var="gadget">
                 <apex:column headerValue="Gadget Type (Name)" value="{!gadget.Name}"/>
                 <apex:column headerValue="Status (Status__c)" value="{!gadget.Status__c}"/>
             </apex:pageBlockTable>
         </apex:pageBlock>         
       </div>
       <div class="col-xs-6">
         <apex:pageBlock title="Item (Item__c)">
            <apex:pageBlockTable value="{!itemlist}" var="item">
               <apex:column headerValue="Item Name (Name)" value="{!item.Name}"/>
               <apex:column headerValue="Type (Lookup,Gadget__c)" value="{!item.Type__c}"/>
            </apex:pageBlockTable>
         </apex:pageBlock>         
       </div>
   </div>

</apex:page>

controller
public class DisplayStatus{
    public List<Gadget__c> gadgetlist {get; set;}
    public List<Item__c> itemlist {get; set;}

    public DisplayStatus()
    {
        this.ShowTable();
    }

    public void ShowTable()
    {
        gadgetlist = [select Name,Status__c from Gadget__c];
        itemlist = [select Name,Type__c from Item__c];
    }
}

It's a bit complicated for me so any help will be much appreciated.
Thanks!
Best Answer chosen by Seraph
Krishna SambarajuKrishna Sambaraju
Here is an update for the trigger. This should work now.
 
trigger UpdateGadgetStatus on Item__c(after insert, after update)
{
    Set<Id> usedGadgetIds = new Set<Id>();
    Set<Id> unUsedGadgetIds = new Set<Id>();
    for (Item__c item : trigger.new)
    {
        if (trigger.isInsert && item.Type__c != null)
        {
            usedGadgetIds.add(item.Type__c);
        }
        if (trigger.isUpdate)
        {
            if (trigger.oldMap.get(item.Id).Type__c != item.Type__c)
            {
                if(item.Type__c != null)
                {
                    usedGadgetIds.add(item.Type__c);
                    if (trigger.oldMap.get(item.Id).Type__c != null)
                    {
                        unUsedGadgetIds.add(trigger.oldMap.get(item.Id).Type__c);
                    }
                }
                else
                {
                    system.debug('Gadget Id: ' + item.Type__c);
                    unUsedGadgetIds.add(trigger.oldMap.get(item.Id).Type__c);
                }
            }
            
        }
    }
    if (usedGadgetIds.size() > 0)
    {
        List<Gadget__c> usedGadgets = [select Id from Gadget__c where Id in :usedGadgetIds];
        for (Gadget__c gadget : usedGadgets)
        {
            gadget.Status__c = 'Used';
        }
        update usedGadgets;
    }
    system.debug('unused gadgetIds size: ' + unUsedGadgetIds.size());
    if (unUsedGadgetIds.size() > 0)
    {
        system.debug('unused gadgets :' + unUsedGadgetIds);
        List<Gadget__c> unUsedGadgets = [select Id from Gadget__c where Id in :unUsedGadgetIds];
        system.debug('unused gadgets size: ' + unUsedGadgets.size());
        for (Gadget__c gadget : unUsedGadgets)
        {
            gadget.Status__c = 'Unused';
        }
        update unUsedGadgets;
    }
}

 

All Answers

Jigar.LakhaniJigar.Lakhani
Hi,

Please try below trigger for your gadget object, it will assign status of gadget based on name with comparing item type.

Apex Trigger
trigger GadgetTrigger on Gadget__c(BEFORE INSERT, BEFORE UPDATE){
	
	// BEFORE INSERT
	if (Trigger.IsBefore && Trigger.IsInsert) {
		List<Gadget__c> listGudgets = new List<Gadget__c>();
		for (Gadget__c objGadget:listGadgets) {
			listGudgets.Add(objGadget);
		}
		if (listGudgets != null && listGudgets.size() > 0) {
			GadgetTriggerHandler.assignGadgetStatus(listGudgets);
		}
	}
	
	// BEFORE Update
	if (Trigger.IsBefore && Trigger.IsUpdate) {
		List<Gadget__c> listGudgets = new List<Gadget__c>();
		for (Gadget__c objGadget:listGadgets) {
			if (objGadget.Name != Trigger.OldMap.Get(objGadget.Id).Name) {
				listGudgets.Add(objGadget);
			}
		}
		if (listGudgets != null && listGudgets.size() > 0) {
			GadgetTriggerHandler.assignGadgetStatus(listGudgets);
		}
	}
	
}

Apex Class
Public Class GadgetTriggerHandler(){
	
	// Assign status to gadgets based on item types
	public static void assignGadgetStatus(List<Gadget__c> listGadgets){
		
		Set<String> setGadgetNames = new Set<String>();
		for (Gadget__c objGadget:listGadgets) {
			setGadgetNames.Add(objGadget.Name);
		}
		
		Set<String> setExistingTypes = new Set<String>();
		for (Item__c objItem:[SELECT Id,Type__c FROM Item__c WHERE Type__c In:setGadgetNames]) {
			setExistingTypes.Add(objItem.Type__c);
		}
		
		List<Gadget__c> listUpdateGadgets = new List<Gadget__c>();
		for (Gadget__c objGadget:listGadgets) {
			if (setExistingTypes.Contains(objGadget.Name)) {
				objGadget.Status__c = 'Used';
			} else {
				objGadget.Status__c = 'Unused';
			}
			listUpdateGadgets.Add(objGadget);
		}
		
		if (listUpdateGadgets != null && listUpdateGadgets.size() > 0) {
			Update listUpdateGadgets;
		}
	}
	
}

Same way, based on that code reference you can write trigger and trigger handler class on Item object.

Thanks & Cheers,
Jigar
SeraphSeraph
Wow...such a fast and detailed reply @Mr Salesforce...
I have few things to ask about your reply (please bear with me as I have only minimal knowledge about triggers for now)
1. Is it not possible to do it all on a trigger (without a handler class)?
2. How did you determine its before insert,before update and not the opposite? (still confused about this)
3. How to post codes like your reply (text editor style)?
Jigar.LakhaniJigar.Lakhani

Hello,

Please see my comments.

1. Is it not possible to do it all on a trigger (without a handler class)?
- Yes, it is possible, you just need to move code from trigger handler class to trigger. But it is the best practice to manage all code in trigger handler class and call these methods from trigger.

2. How did you determine its before insert,before update and not the opposite? (still confused about this)
- We need to determine that based on the requirement exception possibilities, here we can also use after event but in that event you need to manage recursive trigger. if you update the same records in after trigger then that update will again execute the same trigger and it will give exception for recursive trigger. you can handle it using static variable. Update code like below to manage recursive.

- Add one static variable in trigger handler class at the top

public static Boolean blnHandleGadgetRecursive = true;

- Replace the lines which is calling trigger handler method like below at both places

if (listGudgets != null && listGudgets.size() > 0 && GadgetTriggerHandler.blnHandleGadgetRecursive == true) {
			GadgetTriggerHandler.blnHandleGadgetRecursive = false;
			GadgetTriggerHandler.assignGadgetStatus(listGudgets);
			GadgetTriggerHandler.blnHandleGadgetRecursive = true;
		}

And then replace "BEFORE" to "AFTER" at all places in trigger.


3. How to post codes like your reply (text editor style)?

You can format it from "Add a code sample".

User-added image

Thanks & Cheers,
Jigar

SeraphSeraph
I spent some time on your code and I noticed it was triggered via Gadget__c. I haven't tried to implement your code yet but what I was thinking at first is that the trigger was supposed to be like
trigger UpdateStatus on Item__c(after insert,after update){
}

My basis for saying so is that the values for Gadgets__c: Name are already set up by admin and the changes on values (whether they add new items or update its type) will happen much on Items__c since users will be just adding more records on it rather than on Gadgets__c. Is it possible to do it that way?
Jigar.LakhaniJigar.Lakhani
I have added Item trigger and trigger handler.

Apex Trigger
trigger ItemTrigger on Item__c(AFTER INSERT, AFTER UPDATE){
	
	// AFTER INSERT
	if (Trigger.IsAfter && Trigger.IsInsert) {
		List<Item__c> listItems = new List<Item__c>();
		for (Item__c objItem:listItems) {
			listItems.Add(objItem);
		}
		if (listItems != null && listItems.size() > 0) {
			ItemTriggerHandler.assignGadgetStatus(listItems);
		}
	}
	
	// AFTER UPDATE
	if (Trigger.IsAfter && Trigger.IsUpdate) {
		List<Item__c> listItems = new List<Item__c>();
		for (Item__c objItem:listItems) {
			if (objItem.Type__c != Trigger.OldMap.Get(objItem.Id).Type__c) {
				listItems.Add(objItem);
			}
		}
		if (listItems != null && listItems.size() > 0) {
			GadgetTriggerHandler.assignGadgetStatus(listGudgets);
		}
	}
	
}

Apex Class
Public Class ItemTriggerHandler(){
	
	// Assign status to gadgets based on item types
	public static void assignGadgetStatus(List<Item__c> listItems){
		
		Set<String> setItemTypes = new Set<String>();
		for (Item__c objItem:listItems) {
			setItemTypes.Add(objItem.Type__c);
		}
		
		List<Gadget__c> listUpdateGadgets = new List<Gadget__c>();
		for (Gadget__c objGadget:[SELECT Id,Name,Status__c FROM Gadget__c WHERE Name In:setItemTypes]) {
			objGadget.Status__c = 'Used';
		}
		
		if (listUpdateGadgets != null && listUpdateGadgets.size() > 0) {
			Update listUpdateGadgets;
		}
	}
	
}


Thanks & Cheers,
Jigar

SeraphSeraph
The 1st pair you gave (trigger on Gadget__c) ddnt have errors but ddnt work.
I disabled it at the moment and moved on with the next.

I tried the 2nd pair and I get an error on line 23 of trigger ItemTrigger
[Error] Error: Compile Error: Variable does not exist: listGudgets at line 23 column 53



 
SeraphSeraph
I change it to ItemTriggerHandler.assignGadgetStatus(listItems);
it compiled but still not working as it should be...
Jigar.LakhaniJigar.Lakhani
Can you please paste all code here? So I can review it.
Krishna SambarajuKrishna Sambaraju
Hi Seraph,

As per the your screenshot of the objects Gadget__c and Item__c, the Type__c field on the Item__c is a lookup to Gadget__c. You can set the default status on Gadget__c to Unused and use the trigger on the Item__c to update the status on the Gadget__c. Please find the trigger below.
 
trigger UpdateGadgetStatus on Item__c(after insert, after update)
{
	Set<Id> usedGadgetIds = new Set<Id>();
	Set<Id> unUsedGadgetIds = new Set<Id>();
	for (Item__c item : trigger.new)
	{
		if (trigger.isInsert() && item.Type__c != null)
		{
			usedGadgetIds.add(item.Type__c);
		}
		if (trigger.isUpdate())
		{
			if (trigger.oldMap.get(item.Id).Type__c != item.Type__c)
			{
				if(item.Type__c != null)
				{
					usedGadgetIds.add(item.Type__c);
				}
				else
				{
					unUsedGadgetIds.add(item.Type__c);
				}
			}
			
		}
	}
	if (usedGadgetIds.size() > 0)
	{
		List<Gadget__c> usedGadgets = [select Id from Gadget__c where Id in :usedGadgetIds];
		for (Gadget__c gadget : usedGadgets)
		{
			gadget.Status__c = 'Used';
		}
		update usedGadgets;
	}
	if (unUsedGadgetIds.size() > 0)
	{
		List<Gadget__c> unUsedGadgets = [select Id from Gadget__c where Id in :unUsedGadgetIds];
		for (Gadget__c gadget : unUsedGadgetIds)
		{
			gadget.Status__c = 'Unused';
		}
		update unUsedGadgets;
	}
}

You can aswell move the logic to a handler as Jigar suggested.

Hope this helps.

 
SeraphSeraph
trigger
trigger ItemTrigger on Item__c(AFTER INSERT, AFTER UPDATE){
	
	// AFTER INSERT
	if (Trigger.IsAfter && Trigger.IsInsert) {
		List<Item__c> listItems = new List<Item__c>();
		for (Item__c objItem:listItems) {
			listItems.Add(objItem);
		}
		if (listItems != null && listItems.size() > 0) {
			ItemTriggerHandler.assignGadgetStatus(listItems);
		}
	}
	
	// AFTER UPDATE
	if (Trigger.IsAfter && Trigger.IsUpdate) {
		List<Item__c> listItems = new List<Item__c>();
		for (Item__c objItem:listItems) {
			if (objItem.Type__c != Trigger.OldMap.Get(objItem.Id).Type__c) {
				listItems.Add(objItem);
			}
		}
		if (listItems != null && listItems.size() > 0) {
			ItemTriggerHandler.assignGadgetStatus(listItems);
		}
	}
	
}
class
Public Class ItemTriggerHandler(){
	
	// Assign status to gadgets based on item types
	public static void assignGadgetStatus(List<Item__c> listItems){
		
		Set<String> setItemTypes = new Set<String>();
		for (Item__c objItem:listItems) {
			setItemTypes.Add(objItem.Type__c);
		}
		
		List<Gadget__c> listUpdateGadgets = new List<Gadget__c>();
		for (Gadget__c objGadget:[SELECT Id,Name,Status__c FROM Gadget__c WHERE Name In:setItemTypes]) {
			objGadget.Status__c = 'Used';
		}
		
		if (listUpdateGadgets != null && listUpdateGadgets.size() > 0) {
			Update listUpdateGadgets;
		}
	}
	
}



 
Jigar.LakhaniJigar.Lakhani
Hello,

Find the issue, I was miss one line to add.
Please add new line(listUpdateGadgets.Add(objGadget)) at below line(objGadget.Status__c = 'Used') in "ItemTriggerHandler"
So updated code will look like.
for (Gadget__c objGadget:[SELECT Id,Name,Status__c FROM Gadget__c WHERE Name In:setItemTypes]) {
	objGadget.Status__c = 'Used';
	listUpdateGadgets.Add(objGadget);
}

Please try and let me know if it works.
And about Gadget trigger which is not working, please verify that you have updated "AFTER" keyword at all place with "BEFORE" keyword.

Thanks & Cheers,
Jigar


 
SeraphSeraph
@Krishna Sambaraju
Thx for sharing some code...I got this after trying it
Error: Compile Error: Variable does not exist: trigger at line 7 column 13
Krishna SambarajuKrishna Sambaraju
There was a mistake. Here is the correction.
 
trigger UpdateGadgetStatus on Item__c(after insert, after update)
{
	Set<Id> usedGadgetIds = new Set<Id>();
	Set<Id> unUsedGadgetIds = new Set<Id>();
	for (Item__c item : trigger.new)
	{
		if (trigger.isInsert && item.Type__c != null)
		{
			usedGadgetIds.add(item.Type__c);
		}
		if (trigger.isUpdate)
		{
			if (trigger.oldMap.get(item.Id).Type__c != item.Type__c)
			{
				if(item.Type__c != null)
				{
					usedGadgetIds.add(item.Type__c);
				}
				else
				{
					unUsedGadgetIds.add(item.Type__c);
				}
			}
			
		}
	}
	if (usedGadgetIds.size() > 0)
	{
		List<Gadget__c> usedGadgets = [select Id from Gadget__c where Id in :usedGadgetIds];
		for (Gadget__c gadget : usedGadgets)
		{
			gadget.Status__c = 'Used';
		}
		update usedGadgets;
	}
	if (unUsedGadgetIds.size() > 0)
	{
		List<Gadget__c> unUsedGadgets = [select Id from Gadget__c where Id in :unUsedGadgetIds];
		for (Gadget__c gadget : unUsedGadgetIds)
		{
			gadget.Status__c = 'Unused';
		}
		update unUsedGadgets;
	}
}

 
SeraphSeraph
@Mr Salesforce  I tried adding it and compiled it again...still doesnt trigger the status. I don't know why.
@Krishna Sambaraju I used your  revised code and it changed the status to Used after using it as lookup but it didn't change back to    Unused when I changed the lookup to another value.
SeraphSeraph
@Krishna Sambaraju here is how I tested the code you shared

User-added image
Jigar.LakhaniJigar.Lakhani
Hello,

I have reviewed and update trigger and trigger handler code.
Please try with updated code.

Apex Trigger
trigger ItemTrigger on Item__c(AFTER INSERT, AFTER UPDATE){
	
	// AFTER INSERT
	if (Trigger.IsAfter && Trigger.IsInsert) {
		List<Item__c> listItems = new List<Item__c>();
		for (Item__c objItem:Trigger.New) {
			listItems.Add(objItem);
		}
		if (listItems != null && listItems.size() > 0) {
			ItemTriggerHandler.assignGadgetStatus(listItems);
		}
	}
	
	// AFTER UPDATE
	if (Trigger.IsAfter && Trigger.IsUpdate) {
		List<Item__c> listItems = new List<Item__c>();
		for (Item__c objItem:Trigger.New) {
			if (objItem.Type__c != Trigger.OldMap.Get(objItem.Id).Type__c) {
				listItems.Add(objItem);
			}
		}
		if (listItems != null && listItems.size() > 0) {
			ItemTriggerHandler.assignGadgetStatus(listItems);
		}
	}
	
}
Apex Class
Public Class ItemTriggerHandler(){
	
	// Assign status to gadgets based on item types
	public static void assignGadgetStatus(List<Item__c> listItems){
		
		// Update those gadgets which are related to new item type
		Set<String> setNewItemTypes = new Set<String>();
		for (Item__c objItem:listItems) {
			setNewItemTypes.Add(objItem.Type__c);
		}
		
		List<Gadget__c> listUpdateNewGadgets = new List<Gadget__c>();
		for (Gadget__c objGadget:[SELECT Id,Name,Status__c FROM Gadget__c WHERE Name In:setNewItemTypes]) {
			objGadget.Status__c = 'Used';
			listUpdateNewGadgets.Add(objGadget);
		}
		
		if (listUpdateGadgets != null && listUpdateGadgets.size() > 0) {
			Update listUpdateGadgets;
		}
		
		// Update those gadgets which are related to old item type
		// Get all item types to check that if old item type is related to other gadget
		List<Item__c> listItems = new List<Item__c>([SELECT Id,Type__c FROM Item__c WHERE Type__c != null]);
		Set<String> setItemTypes = new Set<String>();
		for (Item__c objItem:listItems) {
			setItemTypes.Add(objItem.Type__c);
		}
		
		List<Gadget__c> listUpdateOldGadgets = new List<Gadget__c>();
		for (Gadget__c objGadget:[SELECT Id,Name,Status__c FROM Gadget__c WHERE Name Not In:setItemTypes]) {
			objGadget.Status__c = 'Unused';
			listUpdateOldGadgets.Add(objGadget);
		}
		
		if (listUpdateOldGadgets != null && listUpdateOldGadgets.size() > 0) {
			Update listUpdateOldGadgets;
		}
	}
	
}

 

Hope it will work this time.
Let me know if it works.

Thanks & Cheers,
Jigar


 

SeraphSeraph
@Mr Salesforce
I got an error on the class
Error: Compile Error: Duplicate variable: listItems at line 24 column 23
Jigar.LakhaniJigar.Lakhani

Please update variable name of list.
Replace "listItems" to "listExistingItems" from line #24 to end of the code.

SeraphSeraph
@Mr Salesforce  It turned everthing into Unused and didn't change from then on even with value changes in Item__c
Krishna SambarajuKrishna Sambaraju
Hi Seraph,

I have found what is wrong with the code I have given. Here is the corrected trigger.
 
trigger UpdateGadgetStatus on Item__c(after insert, after update)
{
    Set<Id> usedGadgetIds = new Set<Id>();
    Set<Id> unUsedGadgetIds = new Set<Id>();
    for (Item__c item : trigger.new)
    {
        if (trigger.isInsert && item.Type__c != null)
        {
            usedGadgetIds.add(item.Type__c);
        }
        if (trigger.isUpdate)
        {
            if (trigger.oldMap.get(item.Id).Type__c != item.Type__c)
            {
                if(item.Type__c != null)
                {
                    usedGadgetIds.add(item.Type__c);
                }
                else
                {
                    unUsedGadgetIds.add(trigger.oldMap.get(item.Id).Type__c);
                }
            }
            
        }
    }
    if (usedGadgetIds.size() > 0)
    {
        List<Gadget__c> usedGadgets = [select Id from Gadget__c where Id in :usedGadgetIds];
        for (Gadget__c gadget : usedGadgets)
        {
            gadget.Status__c = 'Used';
        }
        update usedGadgets;
    }
    if (unUsedGadgetIds.size() > 0)
    {
        List<Gadget__c> unUsedGadgets = [select Id from Gadget__c where Id in :unUsedGadgetIds];
        for (Gadget__c gadget : unUsedGadgets)
        {
            gadget.Status__c = 'Unused';
        }
        update unUsedGadgets;
    }
}

Hope this will work now.
SeraphSeraph
@Krishna Sambarahu ...Sorry if I replied so late..trouble connecting to this site since hours ago.
I tried the latest one and it still behaves the same as the previous one.
Unused to Used = success
Used back to Unused = failed
User-added image
 
Krishna SambarajuKrishna Sambaraju
Here is an update for the trigger. This should work now.
 
trigger UpdateGadgetStatus on Item__c(after insert, after update)
{
    Set<Id> usedGadgetIds = new Set<Id>();
    Set<Id> unUsedGadgetIds = new Set<Id>();
    for (Item__c item : trigger.new)
    {
        if (trigger.isInsert && item.Type__c != null)
        {
            usedGadgetIds.add(item.Type__c);
        }
        if (trigger.isUpdate)
        {
            if (trigger.oldMap.get(item.Id).Type__c != item.Type__c)
            {
                if(item.Type__c != null)
                {
                    usedGadgetIds.add(item.Type__c);
                    if (trigger.oldMap.get(item.Id).Type__c != null)
                    {
                        unUsedGadgetIds.add(trigger.oldMap.get(item.Id).Type__c);
                    }
                }
                else
                {
                    system.debug('Gadget Id: ' + item.Type__c);
                    unUsedGadgetIds.add(trigger.oldMap.get(item.Id).Type__c);
                }
            }
            
        }
    }
    if (usedGadgetIds.size() > 0)
    {
        List<Gadget__c> usedGadgets = [select Id from Gadget__c where Id in :usedGadgetIds];
        for (Gadget__c gadget : usedGadgets)
        {
            gadget.Status__c = 'Used';
        }
        update usedGadgets;
    }
    system.debug('unused gadgetIds size: ' + unUsedGadgetIds.size());
    if (unUsedGadgetIds.size() > 0)
    {
        system.debug('unused gadgets :' + unUsedGadgetIds);
        List<Gadget__c> unUsedGadgets = [select Id from Gadget__c where Id in :unUsedGadgetIds];
        system.debug('unused gadgets size: ' + unUsedGadgets.size());
        for (Gadget__c gadget : unUsedGadgets)
        {
            gadget.Status__c = 'Unused';
        }
        update unUsedGadgets;
    }
}

 
This was selected as the best answer
Krishna SambarajuKrishna Sambaraju
You can remove the debug statements I used in the trigger. 

This trigger will work in 1-1 case. If you have multiple items for each Gadget it might not work.
SeraphSeraph
Here's the result:
User-added image
Krishna SambarajuKrishna Sambaraju
As I already told you it will only work in 1-1 relationship. If you relate multiple items to same gadget, the trigger will not work.
SeraphSeraph
@Krishna Sambaraju...I see...Thanks!
Krishna SambarajuKrishna Sambaraju
Hi Seraph,

If your requirement is for 1:M (One gadget can have multiple items), here is an update of the trigger. Hope this works as per your requirement.
trigger UpdateGadgetStatus on Item__c(after insert, after update)
{
    Set<Id> gadgetIds = new Set<Id>();
    Set<Id> unUsedGadgetIds = new Set<Id>();
    for (Item__c item : trigger.new)
    {
        if (trigger.isInsert && item.Type__c != null)
        {
            gadgetIds.add(item.Type__c);
        }
        if (trigger.isUpdate)
        {
            if (trigger.oldMap.get(item.Id).Type__c != item.Type__c)
            {
                if(item.Type__c != null)
                {
                    gadgetIds.add(item.Type__c);
                    if (trigger.oldMap.get(item.Id).Type__c != null)
                    {
                        gadgetIds.add(trigger.oldMap.get(item.Id).Type__c);
                    }
                }
                else
                {
                    gadgetIds.add(trigger.oldMap.get(item.Id).Type__c);
                }
            }
            
        }
    }
    
    List<Item__c> items = [select Id, Type__c from Item__c where Type__c IN :gadgetIds order by Type__c];
    Map<Id, List<Item__c>> gadgetId2Items = new Map<Id, List<Item__c>>();
    for (Item__c item : items)
    {
        List<Item__c> gadgetItems = gadgetId2Items.get(item.Type__c);
        if (gadgetItems == null)
        {
            gadgetItems = new List<Item__c>();
        }
        gadgetItems.add(item);
        if (item.Type__c != null)
        {
            gadgetId2Items.put(item.Type__c, gadgetItems);
        }
    }
    
    List<Gadget__c> gadgets = [select Id from Gadget__c where Id in :gadgetIds];
    for (Gadget__c gadget : gadgets)
    {
        gadget.Status__c = 'Unused';
        
        if (gadgetId2Items.get(gadget.Id) != null)
        {
            gadget.Status__c = 'Used';
        }
    }
    update gadgets;
}