# Marten Exploration Summary ## What is Marten? Marten is a document database library for .NET that uses PostgreSQL as its storage engine. It provides a NoSQL-like API while leveraging PostgreSQL's JSONB capabilities and ACID compliance. **Key Characteristics:** - Stores .NET objects as JSON documents in PostgreSQL JSONB columns - Provides LINQ query support that translates to PostgreSQL JSON operators - Supports event sourcing patterns - Uses optimistic concurrency control - Handles serialization with opinionated defaults (camel-case properties, enum strings) Both java files go in `src/main/java/com/example/` ## Core Concepts ### Document Storage Pattern Instead of traditional relational tables, Marten stores entire objects as JSON documents: ```sql -- Traditional relational approach CREATE TABLE users ( id UUID, name VARCHAR(100), email VARCHAR(100), created_at TIMESTAMP ); -- Marten approach CREATE TABLE users ( id UUID PRIMARY KEY, data JSONB NOT NULL -- entire object stored here ); ``` ### LINQ to PostgreSQL JSON Marten translates C# LINQ expressions into PostgreSQL JSON operators: ```csharp // C# LINQ session.Query() .Where(u => u.Email.Contains("@example.com")) .OrderBy(u => u.Name) // Becomes PostgreSQL SELECT data FROM users WHERE data->>'email' LIKE '%@example.com%' ORDER BY data->>'name' ``` ### PostgreSQL JSON Operators - `->>` : Extract field as text (`data->>'email'`) - `->` : Extract field as JSON (`data->'address'`) - `@>` : Contains (`data @> '{"name": "Alice"}'`) - `?` : Key exists (`data ? 'email'`) ## Working Example: Raw PostgreSQL JSONB We built a simple example showing what Marten does under the hood: ```java // Store a document Map user = new HashMap<>(); user.put("name", "Alice"); user.put("email", "alice@example.com"); String userJson = mapper.writeValueAsString(user); PreparedStatement insert = conn.prepareStatement( "INSERT INTO users (id, data) VALUES (?::uuid, ?::jsonb)"); insert.setString(1, UUID.randomUUID().toString()); insert.setString(2, userJson); // Query with JSON operators PreparedStatement query = conn.prepareStatement( "SELECT data FROM users WHERE data->>'email' LIKE ?"); query.setString(1, "%@example.com%"); ``` **Key insight:** Marten eliminates this JDBC/JSON boilerplate with a clean object-oriented API. ## Alternative: Jimmer (Java/Kotlin) Jimmer provides similar functionality to Marten for the JVM ecosystem: ### Entity Definition ```java @Entity public interface User { @Id UUID id(); String name(); String email(); LocalDateTime createdAt(); } ``` ### Object Creation ```java User user = UserDraft.$.produce(draft -> { draft.setName("Alice"); draft.setEmail("alice@example.com"); draft.setCreatedAt(LocalDateTime.now()); }); ``` ### Code Generation Like Marten, Jimmer uses code generation at compile time: - Generates `UserDraft` for object creation - Generates `UserTable` for type-safe querying - Handles immutable object implementations ## Development Environment Setup ### Java/Jimmer Path (Working) ```bash # Prerequisites sudo apt install openjdk-17-jdk maven # Project structure mkdir marten-experiment && cd marten-experiment # Create pom.xml with Jimmer dependencies # Create entity interfaces # Maven handles code generation automatically mvn compile && mvn exec:java -Dexec.mainClass="com.example.JimmerExample" ``` ### .NET/Marten Path (Blocked) Corporate laptop restrictions prevented .NET SDK installation. Options to explore: - Request IT approval for .NET SDK - Use WSL2 with different permissions - Try Mono (outdated, not recommended) - Use Visual Studio if available ## Key Patterns Learned ### 1. Document vs Relational Storage - **Relational**: Normalize data across tables with foreign keys - **Document**: Store complete objects as JSON, query within documents - **Hybrid**: Marten/Jimmer allow both patterns in the same database ### 2. Code Generation Benefits - Define data shape once (class/interface) - Generated code handles: - Object creation/mutation - Serialization/deserialization - Type-safe query builders - Database schema management ### 3. Query Translation - Write queries in host language (C# LINQ, Java builder pattern) - Library translates to optimized SQL with JSON operators - Deferred execution - builds expression trees, executes when enumerated ## Event Sourcing Context Marten is popular for event sourcing because: - Events are naturally document-shaped (JSON) - PostgreSQL provides strong consistency guarantees - Built-in stream aggregation and projection capabilities - Can mix event data with traditional relational data ## Next Steps 1. **Get .NET working** - Either through IT approval or alternative approach 2. **Try real Marten examples** - Document storage, event sourcing, projections 3. **Compare with current architecture** - Understand migration implications 4. **Explore Marten's "warts"** - Concurrency handling, performance characteristics, serialization edge cases ## Working Code The Jimmer experiment is ready to extend: - Location: `~/marten-hack/` - Run: `mvn exec:java -Dexec.mainClass="com.example.JimmerExample"` - Generated code: `target/generated-sources/annotations/com/example/UserTable.java` - Add database operations once API is clarified The PostgreSQL container is still running: ```bash docker ps # Check if marten-postgres is running # Connect: docker exec -it marten-postgres psql -U postgres -d marten_test ``` --- ## OTHER STUFF Your gist captures the essential concepts very well! You've got all the important parts. I'd suggest adding just a few missing pieces to make it complete: **1. Add the actual code files** - You mention "Both java files go in src/main/java/com/example/" but don't show them. Include: ```java // User.java package com.example; import org.babyfish.jimmer.sql.*; import java.util.UUID; import java.time.LocalDateTime; @Entity public interface User { @Id UUID id(); String name(); String email(); LocalDateTime createdAt(); } ``` **2. Include the pom.xml** since that was crucial for getting Jimmer working: ```xml org.babyfish.jimmer jimmer-sql 0.8.138 ``` **3. Add one important insight you discovered** - the "SQL backwards" LINQ concept: ``` LINQ is "SQL backwards": - SQL: SELECT name FROM users WHERE age > 25 ORDER BY name - LINQ: users.Where(u => u.Age > 25).OrderBy(u => u.Name).Select(u => u.Name) ``` **4. Mention the Docker PostgreSQL setup** since that was essential: ```bash docker run --name marten-postgres \ -e POSTGRES_PASSWORD=password \ -e POSTGRES_DB=marten_test \ -p 5432:5432 -d postgres:15 ``` Everything else is spot on! You've captured the key insights about document storage, code generation, and the conceptual similarities between Marten and Jimmer.