> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fusioncore.us/llms.txt
> Use this file to discover all available pages before exploring further.

# Caching

> Prevent duplicate SOQL with FCORE_BASE.CacheService: the per-transaction record cache, relationship caching with QueryUnit, and cache invalidation.

`FCORE_BASE.CacheService` is an in-memory, per-transaction record cache that prevents duplicate SOQL. The first request for a given record-and-field combination queries and caches the result; later requests in the same transaction only query the Ids and fields that have not yet been cached.

There are two singletons, one per sharing mode:

* `FCORE_BASE.CacheServiceWithSharing` — respects the running user's sharing rules.
* `FCORE_BASE.CacheServiceWithoutSharing` — ignores sharing.

Get either with `getInstance()`. Most feature code reaches the cache indirectly through a [DB class](/developer-guide/db-classes), which is the preferred way to query an object; use `CacheService` directly when you are writing or extending a DB class.

## Caching Fields on a Record

Use `getById(SObjectType, Id, <fields>)` for a single record and `getByIds(SObjectType, Set<Id>, <fields>)` for many. The id argument is a single `Id` for `getById` and a `Set<Id>` (not a `List`) for `getByIds`. The `<fields>` argument can be a CSV `String`, a `Set<String>`, or a `List<SObjectField>`:

```java theme={null}
// Single record, fields as a CSV string
Account acc = (Account) FCORE_BASE.CacheServiceWithSharing.getInstance()
    .getById(Account.SObjectType, accountId, 'Name, BillingCity');

// Many records, fields as a Set<String>
List<SObject> accounts = FCORE_BASE.CacheServiceWithSharing.getInstance()
    .getByIds(Account.SObjectType, accountIds, new Set<String>{'Name', 'BillingCity'});
```

A second call for the same record and fields is served from the cache with no additional SOQL. If you ask for a field that is not yet cached, only that field is queried.

## Caching Relationships With `QueryUnit`

To cache a parent record together with its child records (a subquery), use a `FCORE_BASE.QueryUnit`. `QueryUnit` is its own top-level class — not an inner class of `CacheService`.

Constructors:

* `QueryUnit(SObjectType, Set<String>)`
* `QueryUnit(SObjectType, List<SObjectField>)`
* `QueryUnit(SObjectType, String)`

Add a child query with `addChildQueryUnit(QueryUnit queryUnit, String relation)`, then pass the parent `QueryUnit` to `getById(QueryUnit, Id)` or `getByIds(QueryUnit, Set<Id>)`:

```java theme={null}
// Parent: Account with Name; child: its Contacts with FirstName/LastName
FCORE_BASE.QueryUnit accountQuery =
    new FCORE_BASE.QueryUnit(Account.SObjectType, new Set<String>{'Name'});

FCORE_BASE.QueryUnit contactQuery =
    new FCORE_BASE.QueryUnit(Contact.SObjectType, new Set<String>{'FirstName', 'LastName'});

accountQuery.addChildQueryUnit(contactQuery, 'Contacts');

Account acc = (Account) FCORE_BASE.CacheServiceWithSharing.getInstance()
    .getById(accountQuery, accountId);
// acc.Contacts is populated from the same cached query
```

## Invalidating the Cache

If you update records and need fresh data later in the same transaction, clear the relevant cache entries:

```java theme={null}
FCORE_BASE.CacheServiceWithSharing.getInstance().clear();                     // everything
FCORE_BASE.CacheServiceWithSharing.getInstance().clear(Account.SObjectType);  // one object
FCORE_BASE.CacheServiceWithSharing.getInstance().clear(accountId);            // one record
```
