Two ways to store a job-site address, benchmarked instead of argued about

Salesforce Location has a VisitorAddressId lookup to a real Address object. It looked like the right answer. Three DMLs, two records, and a circular delete later, plain fields won.

At Doorvana the property is a standard Location record — the garage door opening belongs to a house, and that house outlives whoever owns it. Which raises a dull-sounding question with a surprisingly sharp answer: where does the address go?

Salesforce offers two paths, and one of them looks obviously better on paper.

The path that looks right

Location ships with a VisitorAddressId field. It is not an address — it is a lookup to a record of the standard Address object, which is fully writable and carries Street as a textarea, City, StateCode and CountryCode as real picklists, PostalCode, and its own latitude and longitude.

Compare that to hand-rolling Site_Street__c, Site_City__c, Site_State__c, Site_Postal_Code__c and you appear to be reinventing something Salesforce already built, including the state picklist.

So I built both and measured, rather than reasoning about it in a doc.

What the sandbox said

The Address path needs the Location to exist before the Address can be created, because Address.ParentId is required and points at Location — then the Location has to be updated to point back. Two of its three DMLs exist only to wire the pair together.

Three DML operations against one. But the row count is not what decided it.

The sharp edge: a circular delete

Location.VisitorAddressId points at the Address. Address.ParentId points back at the Location. Neither record can be deleted while the other points at it, and both deletes fail with the same unhelpful message:

could not be completed because it is associated with the following locations

Cleanup is a three-step dance in a fixed order:

  1. null out Location.VisitorAddressId
  2. delete the Address
  3. delete the Location

For most objects that would be an annoyance. For a property base it is a real problem. Properties get merged, de-duplicated, corrected and retired over years — a wrong address typed once in 2027 is still there in 2032 unless someone can remove it. Making deletion a documented procedure rather than a delete button means, in practice, that nobody cleans up.

Two smaller findings in the same test, both disqualifying on their own:

  • Address.LocationType is required and its only available value is Virtual. Every job-site address would be stamped “Virtual”, forever.
  • Address.AddressType offers Mailing, Shipping, Billing and Home. There is no job-site value.

The standard object is not built for this. It is built for corporate addresses.

Correcting my own note while I was at it

I had written in the ERD that empty Lat/Long on Location would break Field Service dispatch. That is wrong, and testing it is what showed me.

Work Order and Service Appointment carry their own standard compound address fields, and routing uses those. A Location with no coordinates does not break scheduling. What it costs is geospatial reporting over the property base — mapping the sites served, analysing coverage by area — which is a real cost but a different one, and worth being accurate about when a client asks whether it matters.

The state field had to be rebuilt anyway

Choosing custom fields means giving up the StateCode picklist the Address object hands you, and that mattered: with free text, “TX”, “Texas” and “tx” are three different states and every report is quietly wrong.

So Site_State__c became a restricted picklist on a US_State global value set — 51 values, Texas default. Which surfaced its own Salesforce limitation.

manifest/destructiveChangesPre.xml

<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <types>
        <members>Location.Site_State__c</members>
        <name>CustomField</name>
    </types>
</Package>

Worth knowing: the API name was reusable immediately, with no purge from Deleted Fields required. Verified afterwards by describe — picklist, restricted, 51 values, TX default.

One more thing fell out of the same pass. Site_City__c was 80 characters and Site_State__c was shorter, which is inverted relative to the standard compound address where City is 40. Nobody would notice until a migration out of these fields into standard address fields truncated somebody’s city. Narrowed to 40 while it was free to do so.

Where this leaves the model

Four plain fields on Location, one of them a restricted picklist on a shared value set. One DML to create a property. A delete button that works.

The Address object is the more sophisticated answer, and for a company managing its own corporate sites it is probably the right one. For a property base that will accumulate tens of thousands of job sites and needs to stay clean, the boring version wins — and it won on numbers I could show the client rather than on taste.

Filed under

Disclosure: Doorvana's owner is also a co-owner of Nocona Consulting. This is a real engagement between two separate companies, but not an arm's-length one — and not an independent reference. More on the work page.

FAQ

Should a Salesforce Location use VisitorAddressId or custom address fields?

For job-site addresses, custom fields on the Location are usually the better answer. VisitorAddressId points at a record of the standard Address object, which requires creating two records and three DML operations to wire together because Address.ParentId is required and points back at the Location. The pair also forms a circular reference that blocks deletion of either record. Custom fields are one DML on one record, at the cost of rebuilding the state picklist yourself.

Why can a Salesforce Location or Address record not be deleted?

When Location.VisitorAddressId points at an Address and that Address's ParentId points back at the Location, the two records reference each other and neither can be deleted while the other exists. Both deletes fail with an error about the record being associated with the following locations. The cleanup order is to null out Location.VisitorAddressId first, then delete the Address, then delete the Location.

Does an empty latitude and longitude on a Location break Field Service scheduling?

No. Work Order and Service Appointment carry their own standard compound address fields and Field Service routing uses those, so a Location with empty Lat/Long does not break dispatch. What it does cost is geospatial reporting across the property base — mapping every site served, or analysing drive time by area.

Can a Salesforce text field be converted to use a global value set?

No. Salesforce rejects converting an existing text field or local picklist to a global value set in place, with the error Cannot change which global value set this picklist uses. The field has to be deleted and recreated on the value set, which means pulling its field-level security first, running a destructive deploy, then restoring the permissions.

Working on something like this?

I can tell you what it takes.

If you run a home services business and this looks like a problem you have, book a call and we will talk through it.