...but that trigger causes other problems; namely, it fires when you attempt to delete a record.
... not only does it fire the script if I delete the record or the relation, but it also fires the script if I attempt to go into layout mode.
Thank you for providing a sample (script is attached to Box Serial Number field in OrderItems portal on Orders table):
Go to Field [ Order Items::Box Serial Number ]
Exit Script [ ]
Set Variable [ $count; Value:Count(boxestb Converted::ser_numb) ]
If [ $count > 0 ]
Exit Script [ Result: True ]
Exit Script [ Result: False ]
I believe it is a difference of semantics; of course if your cursor is in the field, trigger will fire but OnObjectExit does not fire when you delete a record, just as Comment stated, nor when you go into layout mode. It is the field exit which is firing the script and it is doing exactly what it should do as any script trigger will do.
Your script can be shortened a bit. Just checking for ANY (actually the FIRST) related record is faster than counting the related records to see if there is at least one:
If [ not boxes Converted::ser_numb ] // invalid serial number because NO related record found
Show Custom Dialog [ "ERROR" ; "You must enter a valid serial number" ]
Exit Script [ False ]
I notice your serial number is text in OrderItems and Boxestb. This portion not boxes Converted::ser_numb is a boolean test so if there is ever a possibility that your 'serial_number" will contain text only then change it to: IsEmpty ( boxes Converted::ser_numb )
BTW, you will not need the OrderItemsID in the Orders table. :-)