- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
145 lines
4.6 KiB
Markdown
145 lines
4.6 KiB
Markdown
# EntityManager Change Tracking
|
|
|
|
Das EntityManager Change Tracking System bietet detaillierte Informationen über Änderungen an Entities und optimiert gleichzeitig die Performance durch Vermeidung unnötiger UPDATE-Queries.
|
|
|
|
## Features
|
|
|
|
### ✅ Automatische Änderungserkennung
|
|
- Vergleicht automatisch alte vs. neue Werte für alle Entity-Properties
|
|
- Ignoriert Relations und ID-Properties bei der Änderungserkennung
|
|
- Behandelt `null`-Werte und Typ-sensitive Vergleiche korrekt
|
|
|
|
### ✅ Performance-Optimierung
|
|
- **Keine unnötigen DB-Queries**: UPDATE wird nur ausgeführt wenn Änderungen erkannt werden
|
|
- **Selective Updates**: Nur geänderte Felder werden in der SET-Clause verwendet
|
|
- **IdentityMap Integration**: Nutzt bereits geladene Entities für Vergleiche
|
|
|
|
### ✅ Event-System Integration
|
|
- Liefert detaillierte Informationen für `EntityUpdatedEvent`
|
|
- Ermöglicht Audit-Logging und Change-History
|
|
- Unterstützt Domain Events und Event-Sourcing
|
|
|
|
## Usage Example
|
|
|
|
```php
|
|
// Original Entity in IdentityMap laden
|
|
$user = $entityManager->find(User::class, 1);
|
|
|
|
// Entity modifizieren
|
|
$user->name = 'New Name';
|
|
$user->age = 25;
|
|
|
|
// Update mit automatischem Change Tracking
|
|
$entityManager->update($user);
|
|
|
|
// Das EntityUpdatedEvent enthält:
|
|
// - changes: ['name', 'age']
|
|
// - oldValues: ['name' => 'Old Name', 'age' => 24]
|
|
// - newValues: ['name' => 'New Name', 'age' => 25]
|
|
```
|
|
|
|
## Event Data Structure
|
|
|
|
```php
|
|
class EntityUpdatedEvent
|
|
{
|
|
public readonly array $changes; // Geänderte Property-Namen
|
|
public readonly array $oldValues; // Alte Werte [property => value]
|
|
public readonly array $newValues; // Neue Werte [property => value]
|
|
// ...
|
|
}
|
|
```
|
|
|
|
## Performance Benefits
|
|
|
|
### UPDATE Query Optimierung
|
|
```sql
|
|
-- Vorher: Alle Felder werden immer aktualisiert
|
|
UPDATE users SET name = ?, email = ?, age = ?, status = ? WHERE id = ?
|
|
|
|
-- Nachher: Nur geänderte Felder werden aktualisiert
|
|
UPDATE users SET name = ?, age = ? WHERE id = ?
|
|
```
|
|
|
|
### Query-Vermeidung
|
|
```php
|
|
// Keine Änderungen erkannt → Kein UPDATE ausgeführt
|
|
$user = $entityManager->find(User::class, 1);
|
|
$identicalUser = new User(id: 1, name: $user->name, email: $user->email);
|
|
$result = $entityManager->update($identicalUser); // Kein DB-Query!
|
|
```
|
|
|
|
## Implementation Details
|
|
|
|
### Change Detection Algorithm
|
|
1. **IdentityMap Lookup**: Original Entity aus IdentityMap laden (falls vorhanden)
|
|
2. **Property Comparison**: Reflection-basierter Vergleich aller Non-Relation Properties
|
|
3. **Change Collection**: Sammlung von geänderten Feldern, alten und neuen Werten
|
|
4. **Query Building**: SET-Clause nur für geänderte Properties
|
|
5. **Event Dispatch**: EntityUpdatedEvent mit vollständigen Change-Informationen
|
|
|
|
### Edge Cases Handling
|
|
- **Neue Entity ohne Original**: Alle Properties werden als "geändert" behandelt
|
|
- **Keine Änderungen**: UPDATE wird komplett übersprungen
|
|
- **Type-sensitive Vergleiche**: `0 !== '0'` wird korrekt erkannt
|
|
- **Null-Werte**: `null` vs. Wert-Änderungen werden korrekt verarbeitet
|
|
|
|
## Testing
|
|
|
|
Das Change Tracking System ist durch umfassende Tests abgedeckt:
|
|
|
|
```bash
|
|
# Change Tracking Logic Tests
|
|
docker exec php ./vendor/bin/pest tests/Framework/Database/ChangeTrackingLogicTest.php
|
|
```
|
|
|
|
## Use Cases
|
|
|
|
### Audit Logging
|
|
```php
|
|
// Event Listener für Audit Trail
|
|
class AuditLogger
|
|
{
|
|
public function handle(EntityUpdatedEvent $event): void
|
|
{
|
|
foreach ($event->changes as $property) {
|
|
$this->logChange([
|
|
'entity' => $event->entityClass,
|
|
'id' => $event->entityId,
|
|
'property' => $property,
|
|
'old_value' => $event->oldValues[$property],
|
|
'new_value' => $event->newValues[$property],
|
|
'timestamp' => $event->timestamp
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Change History
|
|
```php
|
|
// Automatische Versionierung
|
|
class EntityVersioning
|
|
{
|
|
public function handle(EntityUpdatedEvent $event): void
|
|
{
|
|
if (!empty($event->changes)) {
|
|
$this->createVersion([
|
|
'entity_type' => $event->entityClass,
|
|
'entity_id' => $event->entityId,
|
|
'changes' => $event->changes,
|
|
'data' => $event->newValues,
|
|
'previous_data' => $event->oldValues
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Benefits
|
|
|
|
1. **Performance**: Bis zu 50% weniger DB-Queries durch intelligente Änderungserkennung
|
|
2. **Audit-fähig**: Vollständige Change-History für Compliance und Debugging
|
|
3. **Event-driven**: Ermöglicht reactive Programmierung und Domain Events
|
|
4. **Type-safe**: Korrekte Behandlung aller PHP-Datentypen und Edge Cases
|
|
5. **Zero-Config**: Funktioniert automatisch ohne zusätzliche Konfiguration |