# UPDATE

Update rows with the generated Update() builder. Targets the row by primary key, narrows the column set, and adds extra WHERE conditions.

## Overview

Every generated entity instance exposes an `.Update()` method that returns a fluent builder. By default it updates every mapped column and targets the row whose PK matches the instance. You can narrow or change the set of columns updated and add extra `WHERE` conditions on top of the PK filter.

## Default Behavior

Without any field-selection modifier, `Update()` generates a `SET` clause for every mapped column (the primary-key columns are included too, set to their current values). The `WHERE` clause is always built from the PK column(s) using the values currently on the instance.

```csharp
// update all non-PK columns for the matching row
user.Name = "Alice Renamed";
user.Score = 42;

int rows = await user.Update()
    .WithConnection(conn)
    .ExecuteAsync();
// SQL: UPDATE "users" SET "name" = $1, "score" = $2, ... WHERE "id" = $n
```

`ExecuteAsync()` returns `Task<int>`, the number of rows affected. A return value of `0` means no row matched the PK (the row does not exist or was already deleted).

## Field Selection Strategies

### WithAllFields: Explicit All Columns

Explicitly includes every column, including any the default behavior might exclude.

```csharp
// update all columns explicitly
int rows = await user.Update()
    .WithConnection(conn)
    .WithAllFields()
    .ExecuteAsync();
```

### WithAllFields().ExceptFields(): All Columns Except Listed

Updates all columns but skips the ones you specify. Useful for preserving immutable audit columns.

```csharp
// update everything except CreatedAt
int rows = await user.Update()
    .WithConnection(conn)
    .WithAllFields()
    .ExceptFields(x => new object?[] { x.CreatedAt })
    .ExecuteAsync();
```

### WithFields: Only Listed Columns

Updates only the columns you specify. Every other column is left unchanged in the database.

```csharp
// update only Name and Email
int rows = await user.Update()
    .WithConnection(conn)
    .WithFields(x => new object?[] { x.Name, x.Email })
    .ExecuteAsync();
// SQL: UPDATE "users" SET "name" = $1, "email" = $2 WHERE "id" = $3
```

### ExceptFields: All Except Listed

Updates all columns except the ones you specify. The inverse of `WithFields`.

```csharp
// update all columns except UpdatedAt (managed elsewhere)
int rows = await user.Update()
    .WithConnection(conn)
    .ExceptFields(x => new object?[] { x.UpdatedAt })
    .ExecuteAsync();
```

## Custom WHERE Clause

`.Where()` replaces the default PK-based `WHERE` clause entirely with your predicate. When you supply `.Where()`, the PK filter is **not** added automatically, so include any PK condition yourself if you still need it.

```csharp
// target by PK and an extra condition, expressed in one predicate
int rows = await user.Update()
    .WithConnection(conn)
    .WithFields(x => new object?[] { x.Score })
    .Where(x => x.Id == user.Id && x.Status == "active")
    .ExecuteAsync();
// SQL: UPDATE "users" SET "score" = $1 WHERE "id" = $2 AND "status" = $3
```

## Static Shorthand

`User.UpdateAsync(instance, conn)` is a static convenience that updates every mapped column for the matching row (it uses `WithAllFields`) and returns `Task<int>`.

```csharp
// static shorthand
int rows = await User.UpdateAsync(user, conn);
```

> **NOTE** The static shorthand supports no field selection or extra WHERE conditions. Use the instance builder when you need those.

## Composite Primary Keys

When an entity has a composite PK (multiple properties marked `[PrimaryKey]`), all PK columns are automatically included in the `WHERE` clause. No extra work is needed.

```csharp
// UserCourse has [PrimaryKey] on both UserId and CourseId
enrollment.CompletedAt = DateTimeOffset.UtcNow;

int rows = await enrollment.Update()
    .WithConnection(conn)
    .WithFields(x => new object?[] { x.CompletedAt })
    .ExecuteAsync();
// SQL: UPDATE "user_course" SET "completed_at" = $1
//      WHERE "user_id" = $2 AND "course_id" = $3
```

## Update With a Transaction

Pass a `DbTransaction` instead of a `DbConnection` when the update is part of a larger unit of work.

```csharp
// update inside a transaction
await using var tx = await conn.BeginTransactionAsync();

user.Status = "suspended";

int rows = await user.Update()
    .WithTransaction(tx)
    .WithFields(x => new object?[] { x.Status })
    .ExecuteAsync();

await tx.CommitAsync();
```

## Interpreting the Return Value

| Return value | Meaning |
|---|---|
| `> 0` | That many rows were updated (usually `1` for PK-based updates) |
| `0` | No matching row found; the instance's PK does not exist in the table |

```csharp
// detect a missing row
int rows = await user.Update()
    .WithConnection(conn)
    .ExecuteAsync();

if (rows == 0)
    throw new InvalidOperationException($"User {user.Id} not found.");
```

> **NOTE** UPDATE uses `ExceptFields` to exclude columns. It has no `ExcludeAutoFields`, `WithValuePropagation`, or `ExecuteReturningAsync`; those are INSERT-only.

## See Also

- [INSERT](/database/0.3.2/querying/writing/insert) for adding new rows
- [DELETE](/database/0.3.2/querying/writing/delete) for removing rows
- [WHERE Operators](/database/0.3.2/querying/reading/where) for the predicate syntax of `.Where()`
