# Conditional execution

```json metadata
{
  "schema_version": 2,
  "title": "Conditional execution",
  "description": "Understand how `StackExchange.Redis` uses conditional execution.",
  "categories": ["docs","develop","stack","oss","rs","rc","oss","kubernetes","clients"],
  "tableOfContents": {"sections":[{"id":"when-conditions","title":"When conditions"},{"id":"transaction-conditions","title":"Transaction conditions"}]}

,
  "codeExamples": []
}
```


Most Redis client libraries use transactions with the
[`WATCH`](https://redis.io/docs/latest/commands/watch) command as the main way to prevent
two clients writing to the same key at once (see [Transactions](https://redis.io/docs/latest/develop/using-commands/transactions) for more information). Unfortunately, this approach is
difficult to use explicitly in `StackExchange.Redis`. Its
[multiplexing](https://redis.io/docs/latest/develop/clients/pools-and-muxing) system
is highly efficient and convenient but can also cause bad interactions
when different connections use watched transactions at the same time.

Instead, `StackExchange.Redis` relies more heavily on conditional execution. This comes
in two basic forms, `When` conditions and transaction conditions, both of which
are explained in the sections below.

## `When` conditions

Several commands have variants that only execute if the key they change
already exists (or alternatively, if it doesn't already exist). For
example, the [`SET`](https://redis.io/docs/latest/commands/set) command has the
variants [`SETEX`](https://redis.io/docs/latest/commands/setex) (set when the key exists),
and [`SETNX`](https://redis.io/docs/latest/commands/setnx) (set when the key doesn't exist).

Instead of providing the different variants of these commands, `StackExchange.Redis`
lets you add a `When` condition to the basic command to access its variants.
The following example demonstrates this for the
[`HashSet()`](https://redis.io/docs/latest/commands/hset) command.



```csharp
bool resp7 = db.HashSet("Details", "SerialNumber", "12345");
Console.WriteLine(resp7); // >>> true

db.HashSet("Details", "SerialNumber", "12345A", When.NotExists);
string resp8 = db.HashGet("Details", "SerialNumber");
Console.WriteLine(resp8); // >>> 12345

db.HashSet("Details", "SerialNumber", "12345A");
string resp9 = db.HashGet("Details", "SerialNumber");
Console.WriteLine(resp9); // >>> 12345A
```

The available conditions are `When.Exists`, `When.NotExists`, and the default
`When.Always`.

## Transaction conditions

`StackExchange.Redis` also supports a more extensive set of conditions that you
can add to transactions. They are implemented internally using
[`WATCH`](https://redis.io/docs/latest/commands/watch) commands in a way that is
guaranteed to be safe, without interactions between different clients.
Although conditions don't provide exactly the same behavior as
explicit `WATCH` commands, they are convenient to use and execute
efficiently.

The example below shows how to use the `AddCondition()` method on
a transaction to let it run only if a specified hash key does not
already exist. See
[Pipelines and transactions](https://redis.io/docs/latest/develop/clients/dotnet/transpipe)
for more information about transactions.



```csharp
var watchedTrans = db.CreateTransaction();

watchedTrans.AddCondition(Condition.KeyNotExists("customer:39182"));

var updateTask = watchedTrans.HashSetAsync(
    "customer:39182",
    new HashEntry[]{
        new HashEntry("name", "David"),
        new HashEntry("age", "27")
    }
);

bool succeeded = db.Wait(watchedTrans.ExecuteAsync());
db.Wait(updateTask);
Console.WriteLine(succeeded); // >>> true
```

The table below describes the full set of conditions you can add to
a transaction. Note that you can add more than one condition to the
same transaction if necessary.

| Condition | Description |
| :-- | :-- |
| `HashEqual` | Enforces that the given hash-field must have the specified value. |
| `HashExists` | Enforces that the given hash-field must exist. |
| `HashNotEqual` | Enforces that the given hash-field must not have the specified value. |
| `HashNotExists` | Enforces that the given hash-field must not exist. |
| `KeyExists` | Enforces that the given key must exist. |
| `KeyNotExists` | Enforces that the given key must not exist. |
| `ListIndexEqual` | Enforces that the given list index must have the specified value. |
| `ListIndexExists` | Enforces that the given list index must exist. |
| `ListIndexNotEqual` | Enforces that the given list index must not have the specified value. |
| `ListIndexNotExists` | Enforces that the given list index must not exist. |
| `StringEqual` | Enforces that the given key must have the specified value. |
| `StringNotEqual` | Enforces that the given key must not have the specified value. |
| `HashLengthEqual` | Enforces that the given hash length is a certain value. |
| `HashLengthLessThan` | Enforces that the given hash length is less than a certain value. |
| `HashLengthGreaterThan` | Enforces that the given hash length is greater than a certain value. |
| `StringLengthEqual` | Enforces that the given string length is a certain value. |
| `StringLengthLessThan` | Enforces that the given string length is less than a certain value. |
| `StringLengthGreaterThan` | Enforces that the given string length is greater than a certain value. |
| `ListLengthEqual` | Enforces that the given list length is a certain value. |
| `ListLengthLessThan` | Enforces that the given list length is less than a certain value. |
| `ListLengthGreaterThan` | Enforces that the given list length is greater than a certain value. |
| `SetLengthEqual` | Enforces that the given set cardinality is a certain value. |
| `SetLengthLessThan` | Enforces that the given set cardinality is less than a certain value. |
| `SetLengthGreaterThan` | Enforces that the given set cardinality is greater than a certain value. |
| `SetContains` | Enforces that the given set contains a certain member. |
| `SetNotContains` | Enforces that the given set does not contain a certain member. |
| `SortedSetLengthEqual` | Enforces that the given sorted set cardinality is a certain value. |
| `SortedSetLengthEqual` | Enforces that the given sorted set contains a certain number of members with scores in the given range. |
| `SortedSetLengthLessThan` | Enforces that the given sorted set cardinality is less than a certain value. |
| `SortedSetLengthLessThan` | Enforces that the given sorted set contains less than a certain number of members with scores in the given range. |
| `SortedSetLengthGreaterThan` | Enforces that the given sorted set cardinality is greater than a certain value. |
| `SortedSetLengthGreaterThan` | Enforces that the given sorted set contains more than a certain number of members with scores in the given range. |
| `SortedSetContains` | Enforces that the given sorted set contains a certain member. |
| `SortedSetNotContains` | Enforces that the given sorted set does not contain a certain member. |
| `SortedSetEqual` | Enforces that the given sorted set member must have the specified score. |
| `SortedSetNotEqual` | Enforces that the given sorted set member must not have the specified score. |
| `SortedSetScoreExists` | Enforces that the given sorted set must have the given score. |
| `SortedSetScoreNotExists` | Enforces that the given sorted set must not have the given score. |
| `SortedSetScoreExists` | Enforces that the given sorted set must have the specified count of the given score. |
| `SortedSetScoreNotExists` | Enforces that the given sorted set must not have the specified count of the given score. |
| `StreamLengthEqual` | Enforces that the given stream length is a certain value. |
| `StreamLengthLessThan` | Enforces that the given stream length is less than a certain value. |
| `StreamLengthGreaterThan` | Enforces that the given stream length is greater than a certain value. |

