← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

Data Mapper vs Active Record

architecture Advanced
debt(d7/e7/b7/t5)
d7 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'only careful code review or runtime testing' (d7). While phpstan and deptrac are listed as detection tools, they cannot automatically detect the architectural mismatch of using Active Record for complex domains or Data Mapper for simple CRUD. This requires experienced code review to assess whether the chosen pattern fits the domain complexity. No automated tool can reliably flag 'you used the wrong ORM pattern for your use case.'

e7 Effort Remediation debt — work required to fix once spotted

Closest to 'cross-cutting refactor across the codebase' (e7). Switching from Active Record (Eloquent) to Data Mapper (Doctrine) or vice versa touches virtually every model, repository, and service in the application. The quick_fix describes choosing the right pattern upfront, but correcting a wrong choice requires rewriting entity classes, query logic, and often service layer code across the entire codebase.

b7 Burden Structural debt — long-term weight of choosing wrong

Closest to 'strong gravitational pull' (b7). The ORM pattern choice shapes how every model, repository, and query is written. Per applies_to, this affects web, cli, and queue-worker contexts — essentially the entire application. Every new feature must conform to the chosen pattern, and the accumulated code becomes increasingly expensive to change. Just shy of b9 because it doesn't completely define system shape — other architectural decisions remain independent.

t5 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'notable trap' (t5). The misconception explicitly states developers believe 'Data Mapper is always better than Active Record' — a documented gotcha that experienced developers eventually learn to evaluate contextually. Common mistakes show the trap works both ways: over-engineering with Data Mapper for simple apps, or polluting Active Record models with complex domain logic. The trap is significant but learnable.

About DEBT scoring →

Also Known As

Active Record Data Mapper Eloquent Doctrine

TL;DR

Two ORM patterns: Active Record bakes persistence into the domain object itself; Data Mapper separates the domain object from its persistence mechanism.

Explanation

Active Record (Laravel Eloquent, Rails): the model extends a base class and knows how to save itself (User::find(), $user->save()). Simple, fast to build, works well for CRUD. Data Mapper (Doctrine): the domain object is a plain PHP class with no knowledge of the database; a separate mapper/repository handles persistence. More complex, but allows true domain objects without ORM contamination. DDD practitioners almost always prefer Data Mapper; simple applications are often better served by Active Record.

Diagram

flowchart LR
    subgraph Active Record
        AR_MODEL["User extends Model<br/>$user->save()<br/>User::find(1)"]
        AR_DB[(Database)]
        AR_MODEL <-->|knows about DB| AR_DB
    end
    subgraph Data Mapper
        DM_ENT[User<br/>plain PHP class<br/>no DB knowledge]
        DM_REPO[UserRepository<br/>find, save, delete]
        DM_DB[(Database)]
        DM_ENT <--> DM_REPO <--> DM_DB
    end
style AR_MODEL fill:#d29922,color:#fff
style DM_ENT fill:#238636,color:#fff
style DM_REPO fill:#1f6feb,color:#fff

Common Misconception

Data Mapper is always better than Active Record — for simple CRUD applications, Active Record's simplicity and speed of development significantly outweigh the purity of Data Mapper.

Why It Matters

Active Record pollutes domain objects with ORM methods — User::where(), $user->save() — making domain logic depend on the database layer and making unit testing without a database harder.

Common Mistakes

  • Using Data Mapper complexity for a simple CRUD app — enormous overhead for no benefit.
  • Active Record models with business logic that calls other models directly — creates hidden dependencies.
  • Treating Eloquent models as domain entities in complex domains — mix of concerns makes testing harder.
  • Not using Eloquent's query scopes to encapsulate query logic — raw where() chains scattered everywhere.

Code Examples

✗ Vulnerable
// Active Record domain contamination:
class Order extends Model {
    public function process(): void {
        // Domain logic mixed with ORM calls:
        $this->status = 'processing';
        $this->save();  // Domain object knows about DB
        $this->customer->notify(); // ORM relationship traversal in domain method
    }
}
✓ Fixed
// Data Mapper — clean domain object:
class Order {  // No ORM inheritance — pure domain
    private OrderStatus $status = OrderStatus::Pending;
    private array $events = [];

    public function process(): void {
        $this->status = OrderStatus::Processing;
        $this->events[] = new OrderProcessed($this->id);
        // No DB calls — persistence handled by OrderRepository
    }
}

Added 15 Mar 2026
Edited 19 Apr 2026
Views 21
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 1 ping S 0 pings M 1 ping T 0 pings W 0 pings T 0 pings F 2 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 1 ping S
No pings yesterday
Amazonbot 7 Perplexity 5 Unknown AI 3 Google 2 ChatGPT 1 Ahrefs 1
crawler 18 crawler_json 1
DEV INTEL Tools & Severity
🔵 Info ⚙ Fix effort: Medium
⚡ Quick Fix
Use Active Record (Eloquent) for simple CRUD apps where domain logic is thin; use Data Mapper (Doctrine) when domain logic is complex and you need to keep your domain objects clean of persistence concerns
📦 Applies To
any web cli queue-worker laravel symfony
🔗 Prerequisites
🔍 Detection Hints
Eloquent model with 50+ methods mixing domain logic and persistence; Doctrine used for simple CRUD where Eloquent would be simpler
Auto-detectable: ✗ No phpstan deptrac
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: High ✗ Manual fix Fix: High Context: File Tests: Update

✓ schema.org compliant