# Issue #200: N+1 Query Problem in Member List

## Problem

The `MemberService::findAll()` method (and similar methods) loads members, then makes 3 additional queries per member to fetch addresses, phones, and emails:

```php
public function findAll(?int $limit = null, ?int $offset = null): array {
    $members = $this->memberMapper->findAll($limit, $offset);
    return array_map(function (Member $member) {
        $id = $member->getId();
        $addresses = $this->addressMapper->findByMemberId($id);  // +1 query
        $phones = $this->phoneMapper->findByMemberId($id);        // +1 query
        $emails = $this->emailMapper->findByMemberId($id);        // +1 query
        return $this->buildMemberResponse($member, $addresses, $phones, $emails);
    }, $members);
}
```

For a page of 20 members, this results in **1 + 20×3 = 61 queries**.

## Impact

- Slow page loads, especially with pagination
- Increased database load
- Poor performance on larger member lists

## Solution

Create a new mapper method that uses JOINs to fetch all data in a single query:

```sql
SELECT m.*, a.*, p.*, e.*
FROM mv_members m
LEFT JOIN mv_addresses a ON m.id = a.member_id
LEFT JOIN mv_phones p ON m.id = p.member_id
LEFT JOIN mv_emails e ON m.id = e.member_id
WHERE m.deleted_at IS NULL
ORDER BY m.nachname, m.vorname
```

Then parse the result set in PHP to group related sub-entities.

## Tasks

- [ ] Create `MemberMapper::findAllWithRelations(?int $limit, ?int $offset): array` that returns raw joined data
- [ ] Create a DTO or use an associative array to represent joined results
- [ ] Update `MemberService::findAll()` to use the new method
- [ ] Apply same pattern to `findFiltered()`, `findByFamily()`, `search()`, `fullTextSearch()`
- [ ] Benchmark before/after query counts

## Labels

- enhancement
- backend
- priority:high
- performance