0ffc993d3f
Database Portability Tests / Unit Tests (PlatformHelper) (pull_request) Failing after 37s
Database Portability Tests / Integration (mysql) (pull_request) Has been skipped
Database Portability Tests / Integration (postgres) (pull_request) Has been skipped
Database Portability Tests / Integration (sqlite) (pull_request) Has been skipped
Database Portability Tests / Verify no MySQL-specific SQL (pull_request) Successful in 5s
1.7 KiB
1.7 KiB
Issue #203: Missing Database Transactions in MemberService
Problem
The MemberService::create() method inserts a member and its sub-entities (addresses, phones, emails) in separate queries without a transaction:
public function create(array $data, array $addresses = [], ...): array {
// ...
$member = $this->memberMapper->insert($member);
$savedAddresses = $this->saveAddresses($member->getId(), $addresses);
$savedPhones = $this->savePhones($member->getId(), $phones);
$savedEmails = $this->saveEmails($member->getId(), $emails);
// ...
}
If savePhones() fails, the member is created but phones are not attached.
Similarly, softDelete() deletes sub-entities separately without a transaction.
Impact
- Data inconsistency if partial failures occur
- Orphaned sub-entities on failed member creation
- Orphaned member on failed sub-entity creation
Solution
Wrap the operation in a transaction:
use OCP\DB\Events\SQLFileEmitter;
public function create(array $data, ...): array {
$this->db->beginTransaction();
try {
$member = $this->memberMapper->insert($member);
$savedAddresses = $this->saveAddresses($member->getId(), $addresses);
// ...
$this->db->commit();
} catch (\Exception $e) {
$this->db->rollback();
throw $e;
}
}
Tasks
- Add transaction wrapping to
MemberService::create() - Add transaction wrapping to
MemberService::softDelete() - Add transaction wrapping to
MemberService::update()(sync operations) - Verify rollback works correctly on failure
- Consider adding a
DbTransactionTraitfor reusability
Labels
- bug
- backend
- priority:high
- data-integrity