---
title: Check preference existence
summary: Count matching preference rows to decide whether SavePreferences should update or insert.
status: draft
owner: SAIF Team
last_reviewed: 2026-07-30
library: SAIF.Framework.Preferences
reference_type: package
operation_id: OP-PREF-007
trigger: SavePreferences calls PreferenceData.DoesPrefExist
---

# Check preference existence

This internal read operation runs a scalar `Count(*)` query for the application/user/page scope and converts the returned count into the Boolean decision that `SavePreferences` uses to choose insert versus update.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-PREF-007 |
| **Trigger** | `SavePreferences` calls `DoesPrefExist(appName, pageName, userId)`. |
| **Inputs** | `appName`, `pageName`, `userId` |
| **Outputs** | `true` when the scoped count is greater than zero; otherwise `false` |
| **Primary components** | `PreferenceData.DoesPrefExist`, `SqlHelper.ScalarQuery<int>` |
| **Entry point** | `SAIF.Framework.Preferences\PreferenceData.cs` |

## Steps

1. Start with the base `select Count(*)` statement for [USER_PREFERENCE](../database-tables.md#user_preference) filtered by `USER_ID` and `APP_NAME` ([SQL-007](../sql/SQL-007-does-pref-exist.md), [USER_PREFERENCE](../database-tables.md#user_preference)).
2. Create a `SqlHelper.ScalarQuery<int>`, reset the parameter list, and bind `:userid` as `userId.ToLower()` plus `:appname` as the application name ([BR-001](../business-rules.md#br-001-user-ids-are-normalized-to-lower-case), [SQL-007](../sql/SQL-007-does-pref-exist.md), [USER_PREFERENCE](../database-tables.md#user_preference)).
3. Apply optional page scoping ([BR-003](../business-rules.md#br-003-preference-identity-is-scoped-by-app-user-and-optional-page), [SQL-007](../sql/SQL-007-does-pref-exist.md), [USER_PREFERENCE](../database-tables.md#user_preference)).
   - If `pageName` is empty, append `and PAGE_NAME is NULL`.
   - If `pageName` is present, append `and PAGE_NAME = :pagename` and bind the page parameter.
4. Attach the parameters and execute the scalar count request through the active portal ([SQL-007](../sql/SQL-007-does-pref-exist.md), [USER_PREFERENCE](../database-tables.md#user_preference)).
   - Create the portal request in the `SqlHelper.ScalarQuery<int>` constructor.
   - Add the bind variables to `DataRequest` through `AddParms`.
   - Set `DataRequest.RequestType` to `Scalar` and `DataRequest.SQLStatement` to the count SQL.
   - Call `IDataPortalInfo.ProcessPortalRequest`, then cast `DataRequest.Result` to `int`.

   > **Origin**: Steps 4.1–4.4 are implemented by [Execute a data portal request](../../saif-framework-core/operations/execute-data-portal-request.md) (`SAIF.Framework.Core`) and executed on behalf of this operation.
5. Compare the returned count to zero and return the Boolean result.
   - On failure: portal and data-provider exceptions propagate because this method has no local recovery logic.

## Process flow

The following diagram visualizes this operation's control flow.

```mermaid
flowchart TD
	Start([DoesPrefExist called]) --> Scope[Apply page-specific count scope]
	Scope --> Execute[Execute COUNT(*)]
	Execute --> Found{Count > 0?}
	Found -->|Yes| Yes([Return true])
	Found -->|No| No([Return false])
```

## Failure and edge-case behavior

- Empty `pageName` scopes the count to rows whose `PAGE_NAME` is `NULL`.
- Any positive count is treated as existence; the method does not verify or enforce that at most one row matches.
- Exceptions from portal execution are not handled locally and surface to the caller unmodified.

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

## Sources
- SAIF.Framework.Preferences\PreferenceData.cs
- SAIF.Framework.Core\V1\DataAccessLayer\SqlHelper.vb
