updateOne method

Future<void> updateOne(
  1. TRow row, {
  2. Set<String>? columns,
})

update, but insisting that exactly one row changed.

The write runs inside a transaction, so a count that turns out wrong leaves nothing behind.

The three outcomes get three different exceptions, because they mean three different things to whoever has to fix them:

  • No row — MssqlRowNotFoundException. The write targets one row by its primary key, so zero means that row is not there, or a scope hides it; the same conclusion getById reports.
  • More than one row — StateError naming the key. A primary key cannot match twice, so this says the declared key does not identify a row: a schema or binding problem, not a data one. Reporting it as an affected-row count would point at the wrong thing.
  • Exactly one — the write stands.

Either failure rolls the write back before the exception leaves.

Implementation

Future<void> updateOne(TRow row, {Set<String>? columns}) async {
  _requireKey('updateOne');
  _checkDecimalAgreement();
  if (columns != null) _checkColumnSubset(columns);
  final values = _stampUpdate(
    _writableValues(row, only: columns, excludeKey: true),
  );
  if (values.isEmpty) {
    throw StateError(
      'Updating ${binding.qualifiedName} would write no columns.',
    );
  }
  final engine = await _engine();
  try {
    await engine.guard(
      operation: 'updateOne',
      expected: 1,
      write: (scoped) => _updateKeyed(row, values, engine: scoped),
    );
  } on MssqlAffectedRowsException catch (error) {
    final source = binding.toColumns(row);
    final key = <String, Object?>{
      for (final name in binding.primaryKey) name: source[name],
    };
    if (error.actual == 0) {
      throw MssqlRowNotFoundException(binding.qualifiedName, key);
    }
    throw StateError(
      'updateOne on ${binding.qualifiedName} changed ${error.actual} rows '
      'for key $key, so the declared primary key '
      '(${binding.primaryKey.join(', ')}) does not identify a single row '
      'in this table. That is a schema or a binding problem rather than a '
      'data one, which is why it is not reported as an affected-row count. '
      'The write was rolled back.',
    );
  }
}