---
title: Provider retrieval
summary: Retrieves a single provider by provider ID or primary tax ID, and retrieves filtered provider collections, exposing provider header data and its tax ID and location aggregates.
status: draft
owner: SAIF Doc Gen
last_reviewed: 2026-07-30
library: SAIF.Business.View.Provider
reference_type: package
operation_id: OP-VP-01
trigger: Caller calls clsProvider.GetProvider(dpi, providerID) or GetProvider(dpi, primaryTaxID), or clsProviderCollection.GetProviderCollection(dpi, taxIDs) / GetProvidersUsingWhere(dpi, whereClause)
---

# Provider retrieval

Provider retrieval reads the `PROVIDER` header row — joined to its primary tax ID row for a formatted tax ID and registered name — either as a single `clsProvider` object or as a `clsProviderCollection`. The single-object factory overloads on parameter type to select between a provider-ID lookup and a primary-tax-ID lookup; the collection factory supports either an explicit list of primary tax IDs or an arbitrary caller-supplied `WHERE` clause. The retrieved provider exposes its locations, tax IDs, and payee-facing address/phone/name through lazily loaded child properties.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-VP-01 |
| **Trigger** | `clsProvider.GetProvider(inDataportal, inProviderID)`; `clsProvider.GetProvider(inDataportal, inPrimaryTaxID)`; `clsProviderCollection.GetProviderCollection(inDataportal, inPrimaryTaxIDs())`; `clsProviderCollection.GetProvidersUsingWhere(inDataportal, inWhereClause)` |
| **Inputs** | Provider ID (Decimal), or primary tax ID (String), or an array of primary tax IDs, or a caller-supplied SQL `WHERE` clause fragment |
| **Outputs** | A read-only `clsProvider` (single retrieval) or a populated `clsProviderCollection`; lazily resolved `ProviderLocations`, `TaxIDs`, and `PrimaryLocation`/payee properties |
| **Primary components** | `clsProvider.GetProvider`, `clsProvider.Criteria`, `clsProviderCollection.GetProviderCollection`, `clsProviderCollection.GetProvidersUsingWhere`, `clsProviderCollection.Criteria` |
| **Entry point** | `Business\SAIF.Business.View.Provider\clsProvider.vb` |

## Steps

1. **Select the single-provider lookup key.** `GetProvider` is overloaded: passing a Decimal constructs a criteria with `CriteriaRetrieveTypes.GetByProviderID`; passing a String constructs a criteria with `CriteriaRetrieveTypes.GetByPrimaryTaxID`. The criteria retains whichever key was supplied.
2. **Bind the retrieve parameter.** `BeforeRetrieve` selects the base `SELECT` joining `PROVIDER` to `PROVIDER_TAX_ID` on the primary tax ID and binds either `:PrimaryTaxID` or `:ProviderID` depending on the criteria's retrieve type ([SQL-003](../sql/SQL-003-saif-business-view-provider.md), [SQL-004](../sql/SQL-004-saif-business-view-provider.md), [PROVIDER](../database-tables.md#provider), [PROVIDER_TAX_ID](../database-tables.md#provider_tax_id)).
3. **Read the single row.** `AfterRetrieve` reads at most one row from the result set, fills the object's provider ID, primary tax ID, formatted tax ID, and registered name, and marks the object as previously persisted (`MarkOld`).
   - If no row matches: the object remains in its default (empty) state; no exception is raised.
4. **Mark the object read-only.** `GetProvider` sets `ReadOnly = True` on the returned object before returning it, so callers cannot save changes back through this path.
5. **Retrieve a provider collection by tax ID list.** `GetProviderCollection` builds a criteria carrying the supplied array of primary tax IDs.
6. **Retrieve a provider collection by arbitrary WHERE clause.** `GetProvidersUsingWhere` builds a criteria carrying the caller-supplied `WHERE` clause fragment verbatim.
   - The caller is responsible for supplying a syntactically valid `WHERE` clause; no validation or sanitization is performed on this input.*
7. **Compose the collection SQL.** The collection criteria's `RetrieveSQL` reuses `clsProvider.Criteria.RETRIEVE_SELECT_SQL` and appends either the tax-ID `IN (...)` predicate built from the supplied array, or the caller's raw `WHERE` clause if one was supplied instead ([SQL-007](../sql/SQL-007-saif-business-view-provider.md), [PROVIDER](../database-tables.md#provider), [PROVIDER_TAX_ID](../database-tables.md#provider_tax_id)).
8. **Populate the collection.** `AfterRetrieve` iterates the result set, constructs a `clsProvider` per row, calls `Load` on each (which fills the row and marks it old), and adds each to the collection.
9. **Resolve lazy child data on demand.** Reading `ProviderLocations` on a populated `clsProvider` triggers a location-collection retrieval by provider ID; reading `TaxIDs` triggers a tax ID collection retrieval by provider ID; both are cached on first access.

   > **Origin**: `ProviderLocations` delegates to the [Provider location retrieval](provider-location-retrieval.md) operation, and `TaxIDs` delegates to the [Provider tax ID retrieval](provider-tax-id-retrieval.md) operation, both implemented in this library.
10. **Resolve payee-facing properties.** `PayeeAddress` resolves the active tax-ID address whose effective/expiration window covers today and whose tax ID matches the primary location's provider's primary tax ID, falling back to the primary location's active payment address when no matching tax-ID address is found; `PayeeID` returns the provider ID as a string; `PayeeTypeCode` is the fixed literal `"PROV"`.

## Process flow

The following diagram visualizes this operation's control flow.

```mermaid
flowchart TD
	Start([GetProvider or GetProviderCollection called]) --> Which{Single or collection?}
	Which -->|Single, by ID| SingleID[Bind ProviderID parameter]
	Which -->|Single, by tax ID| SingleTax[Bind PrimaryTaxID parameter]
	Which -->|Collection, tax ID list| CollTax[Build tax ID IN clause]
	Which -->|Collection, WHERE clause| CollWhere[Use caller supplied WHERE clause]
	SingleID --> Exec1[Execute retrieve query]
	SingleTax --> Exec1
	Exec1 --> Row{Row found?}
	Row -->|Yes| Fill1[Fill object; MarkOld; set ReadOnly]
	Row -->|No| Empty1([Empty object returned; no exception])
	CollTax --> Exec2[Execute retrieve query]
	CollWhere --> Exec2
	Exec2 --> Loop[For each row: create clsProvider,<br>Load, add to collection]
	Loop --> Done2([Populated collection returned])
	Fill1 --> Done1([Read only provider returned])
```

## Failure and edge-case behavior

- A single-provider lookup that matches no row returns an object in its default state rather than throwing; callers must check for a zero/default provider ID to detect a miss.
- `GetProvidersUsingWhere` accepts a raw SQL fragment from the caller with no validation, so a malformed or malicious `WHERE` clause is a caller responsibility, not something this operation guards against.*
- The returned single-provider object is marked read-only, so any attempt to persist changes back through the standard save path is blocked by that flag rather than by a business rule.
- `PayeeAddress` resolution depends on `PrimaryLocation` and `TaxIDs` both being resolvable; if a provider has no locations, `PrimaryLocation` returns `Nothing` and the subsequent address lookup dereferences it, a code path not explicitly guarded against.*

## Related documentation

- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)
- [SQL catalog](../sql/index.md)
- [Database tables](../database-tables.md)

> **Note:** Statements marked with `*` were inferred from code structure, naming
> conventions, or contextual evidence where direct confirmation was not available
> in source artifacts.

## Sources

- `Business\SAIF.Business.View.Provider\clsProvider.vb`
- `Business\SAIF.Business.View.Provider\clsProviderCollection.vb`
