diff --git a/.kiro/specs/operation-samples-showcase/design.md b/.kiro/specs/operation-samples-showcase/design.md
new file mode 100644
index 0000000..92b0672
--- /dev/null
+++ b/.kiro/specs/operation-samples-showcase/design.md
@@ -0,0 +1,278 @@
+# Design Document: Operation Samples Showcase
+
+## Overview
+
+This project provides a standalone .NET 8 class library containing compilable code samples that demonstrate FluentDynamoDb API usage compared to the raw AWS SDK for DynamoDB. The samples are designed for screenshots and video presentations, showing the verbosity reduction and API improvements offered by FluentDynamoDb.
+
+The project uses a simple Order/OrderLine domain with a single-table design pattern. Each DynamoDB operation type has a dedicated sample file containing four methods demonstrating different coding styles:
+1. Raw AWS SDK with explicit AttributeValue dictionaries
+2. FluentDynamoDb manual builder with WithAttribute()/WithValue()
+3. FluentDynamoDb formatted string with {0}, {1} placeholders
+4. FluentDynamoDb lambda expressions with entity accessors
+
+## Architecture
+
+```
+examples/
+└── OperationSamples/
+ ├── OperationSamples.csproj
+ ├── Models/
+ │ ├── Order.cs
+ │ ├── OrderLine.cs
+ │ └── OrdersTable.cs
+ └── Samples/
+ ├── GetSamples.cs
+ ├── PutSamples.cs
+ ├── UpdateSamples.cs
+ ├── DeleteSamples.cs
+ ├── QuerySamples.cs
+ ├── ScanSamples.cs
+ ├── TransactionGetSamples.cs
+ ├── TransactionWriteSamples.cs
+ ├── BatchGetSamples.cs
+ └── BatchWriteSamples.cs
+```
+
+The project is located under the `examples/` folder alongside other example projects (InvoiceManager, StoreLocator, TodoList, TransactionDemo).
+
+### DynamoDB Table Schema
+
+Single-table design with the following key structure:
+- **Table Name**: `Orders`
+- **Partition Key (pk)**: `ORDER#{OrderId}`
+- **Sort Key (sk)**:
+ - `META` for Order metadata
+ - `LINE#{LineId}` for OrderLine items
+
+### Sample Method Naming Convention
+
+Each sample file contains a static class with four methods following this pattern:
+- `RawSdk{Operation}Async` - Direct AWS SDK usage
+- `FluentManual{Operation}Async` - FluentDynamoDb with manual expressions
+- `FluentFormatted{Operation}Async` - FluentDynamoDb with format strings
+- `FluentLambda{Operation}Async` - FluentDynamoDb with lambda expressions
+
+## Components and Interfaces
+
+### Models
+
+#### Order Entity
+```csharp
+[DynamoDbEntity]
+public partial class Order : IDynamoDbEntity
+{
+ [PartitionKey]
+ public string Pk { get; set; } // "ORDER#{OrderId}"
+
+ [SortKey]
+ public string Sk { get; set; } // "META"
+
+ public string OrderId { get; set; }
+ public string CustomerId { get; set; }
+ public DateTime OrderDate { get; set; }
+ public string Status { get; set; } // "Pending", "Shipped", "Delivered"
+ public decimal TotalAmount { get; set; }
+}
+```
+
+#### OrderLine Entity
+```csharp
+[DynamoDbEntity]
+public partial class OrderLine : IDynamoDbEntity
+{
+ [PartitionKey]
+ public string Pk { get; set; } // "ORDER#{OrderId}"
+
+ [SortKey]
+ public string Sk { get; set; } // "LINE#{LineId}"
+
+ public string LineId { get; set; }
+ public string ProductId { get; set; }
+ public string ProductName { get; set; }
+ public int Quantity { get; set; }
+ public decimal UnitPrice { get; set; }
+}
+```
+
+#### OrdersTable
+```csharp
+public partial class OrdersTable : DynamoDbTableBase
+{
+ public OrdersTable(IAmazonDynamoDB client) : base(client, "Orders") { }
+
+ // Generated entity accessors:
+ // public OrderAccessor Orders { get; }
+ // public OrderLineAccessor OrderLines { get; }
+}
+```
+
+#### OrderUpdateModel (for lambda expression updates)
+```csharp
+///
+/// Update model for Order entity used with lambda expression Set() operations.
+///
+public class OrderUpdateModel
+{
+ [DynamoDbAttribute("orderStatus")]
+ public string? Status { get; set; }
+
+ [DynamoDbAttribute("modifiedAt")]
+ public DateTime? ModifiedAt { get; set; }
+
+ [DynamoDbAttribute("totalAmount")]
+ public decimal? TotalAmount { get; set; }
+}
+```
+
+### Sample File Structure
+
+Each sample file follows this structure:
+```csharp
+namespace FluentDynamoDb.OperationSamples.Samples;
+
+public static class {Operation}Samples
+{
+ // Returns AWS SDK response, then converts to domain model for equivalency
+ public static async Task RawSdk{Operation}Async(IAmazonDynamoDB client, ...) { }
+ public static async Task FluentManual{Operation}Async(OrdersTable table, ...) { }
+ public static async Task FluentFormatted{Operation}Async(OrdersTable table, ...) { }
+ public static async Task FluentLambda{Operation}Async(OrdersTable table, ...) { }
+}
+```
+
+### Lambda Expression Patterns
+
+FluentLambda methods should demonstrate the full power of lambda expressions:
+
+#### Update Operations
+```csharp
+// Use Set(x => new UpdateModel { ... }) syntax
+await table.Orders.Update(pk, sk)
+ .Set(x => new OrderUpdateModel
+ {
+ Status = newStatus,
+ ModifiedAt = modifiedAt
+ })
+ .UpdateAsync();
+```
+
+#### Condition Expressions
+```csharp
+// Use AttributeExists/AttributeNotExists via lambda
+await table.Orders.Put(order)
+ .Where(x => x.Pk.AttributeNotExists())
+ .PutAsync();
+
+await table.Orders.Update(pk, sk)
+ .Where(x => x.Pk.AttributeExists())
+ .Set(x => new OrderUpdateModel { Status = newStatus })
+ .UpdateAsync();
+```
+
+#### Express-Route Methods
+```csharp
+// Use express-route methods instead of builder chains
+await table.Orders.PutAsync(order); // NOT: Put(order).PutAsync()
+var order = await table.Orders.GetAsync(pk, sk); // NOT: Get(pk, sk).GetItemAsync()
+await table.Orders.DeleteAsync(pk, sk); // NOT: Delete(pk, sk).DeleteAsync()
+```
+
+### Response Handling Pattern
+
+Raw SDK methods should demonstrate full equivalency by converting responses to domain models:
+
+```csharp
+public static async Task RawSdkGetAsync(IAmazonDynamoDB client, string orderId)
+{
+ var response = await client.GetItemAsync(request);
+
+ if (response.Item == null || response.Item.Count == 0)
+ return null;
+
+ // Manual conversion to show equivalency
+ return new Order
+ {
+ Pk = response.Item["pk"].S,
+ Sk = response.Item["sk"].S,
+ OrderId = response.Item["orderId"].S,
+ // ... other properties
+ };
+}
+```
+
+## Data Models
+
+### Key Patterns
+
+| Entity | Partition Key | Sort Key |
+|--------|--------------|----------|
+| Order | `ORDER#{OrderId}` | `META` |
+| OrderLine | `ORDER#{OrderId}` | `LINE#{LineId}` |
+
+### Sample Data Values
+
+For consistency across samples:
+- OrderId: `"ORD-001"`, `"ORD-002"`
+- LineId: `"LN-001"`, `"LN-002"`
+- CustomerId: `"CUST-123"`
+- Status values: `"Pending"`, `"Shipped"`, `"Delivered"`
+
+## Correctness Properties
+
+*A property is a characteristic or behavior that should hold true across all valid executions of a system-essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.*
+
+Based on the prework analysis, most requirements for this showcase project are structural/stylistic and not amenable to property-based testing. The primary testable property is:
+
+### Property 1: Sample File Method Structure
+*For any* sample file in the Samples folder, the file SHALL contain exactly four public static async Task methods with names matching the patterns: `RawSdk*Async`, `FluentManual*Async`, `FluentFormatted*Async`, and `FluentLambda*Async`.
+
+**Validates: Requirements 1.1**
+
+### Verification Examples (Not Properties)
+
+The following requirements are verified through specific examples rather than universal properties:
+
+- **Build Verification**: Running `dotnet build` produces exit code 0 (Requirements 3.1)
+- **Project Configuration**: The csproj contains `net8.0` and `enable` (Requirements 3.2, 3.3)
+- **Model Files Exist**: `Order.cs` and `OrderLine.cs` exist in Models folder (Requirements 4.1)
+- **Namespace Consistency**: All files use `FluentDynamoDb.OperationSamples` namespace (Requirements 4.4)
+- **Sample Files Exist**: All 10 sample files exist (Requirements 5.1-5.10)
+
+## Error Handling
+
+Since this is a showcase project that doesn't execute against real AWS resources, error handling is minimal:
+
+- Methods may throw `NotImplementedException` only if absolutely necessary for compilation (avoided per requirements)
+- No try-catch blocks needed as code is for demonstration only
+- AWS SDK exceptions are not handled as the code won't execute
+
+## Testing Strategy
+
+### Dual Testing Approach
+
+Given the nature of this showcase project (compilable but non-executable code), testing focuses on:
+
+#### Unit Tests
+- Verify project compiles successfully with `dotnet build`
+- Verify all expected files exist in the correct locations
+- Verify namespace consistency across all files
+
+#### Property-Based Tests
+
+**Property-Based Testing Library**: FsCheck with xUnit integration
+
+**Property 1 Implementation**: Sample File Method Structure
+```csharp
+// Feature: operation-samples-showcase, Property 1: Sample File Method Structure
+// Validates: Requirements 1.1
+[Property]
+public Property AllSampleFilesHaveFourMethods()
+{
+ // For each sample file, verify it contains exactly 4 methods
+ // with the correct naming patterns
+}
+```
+
+### Test Configuration
+- Property tests run minimum 100 iterations
+- Tests tagged with feature and property references per design requirements
diff --git a/.kiro/specs/operation-samples-showcase/requirements.md b/.kiro/specs/operation-samples-showcase/requirements.md
new file mode 100644
index 0000000..473f52b
--- /dev/null
+++ b/.kiro/specs/operation-samples-showcase/requirements.md
@@ -0,0 +1,116 @@
+# Requirements Document
+
+## Introduction
+
+This document specifies requirements for a standalone .NET 8 example project that demonstrates FluentDynamoDb API usage compared to the raw AWS SDK for DynamoDB. The project's sole purpose is to provide clean, compilable code samples suitable for screenshots and video presentations. The code must compile but does not need to execute against real AWS resources.
+
+## Glossary
+
+- **FluentDynamoDb**: The Oproto.FluentDynamoDb library providing fluent-style API wrappers for DynamoDB operations
+- **Raw SDK**: Direct usage of AWSSDK.DynamoDBv2 without any abstraction layers
+- **Manual Builder**: FluentDynamoDb style using explicit expression strings with WithAttribute() and WithValue() methods
+- **Formatted String**: FluentDynamoDb style using C# string interpolation with positional placeholders like {0}, {1}
+- **Lambda Mode**: FluentDynamoDb style using strongly-typed lambda expressions and entity accessors
+- **Entity Accessor**: Generated type-safe property on a table class providing direct access to entity operations (e.g., table.Orders)
+- **Operation Sample**: A set of four methods demonstrating the same DynamoDB operation in different coding styles
+
+## Requirements
+
+### Requirement 1
+
+**User Story:** As a developer evaluating FluentDynamoDb, I want to see side-by-side code comparisons for each DynamoDB operation type, so that I can understand the verbosity reduction and API improvements.
+
+#### Acceptance Criteria
+
+1. WHEN a sample file is created for an operation type THEN the System SHALL include exactly four public static async methods: RawSdk, FluentManual, FluentFormatted, and FluentLambda variants
+2. WHEN the Raw SDK method is implemented THEN the System SHALL use only AWSSDK.DynamoDBv2 types with explicit AttributeValue dictionaries and string-based expressions
+3. WHEN the FluentManual method is implemented THEN the System SHALL use FluentDynamoDb builders with WithAttribute() and WithValue() method calls
+4. WHEN the FluentFormatted method is implemented THEN the System SHALL use FluentDynamoDb builders with positional placeholder strings like {0}, {1}
+5. WHEN the FluentLambda method is implemented THEN the System SHALL use strongly-typed lambda expressions with entity accessor properties, including Set(x => new UpdateModel { ... }) for updates and Where(x => x.Property.AttributeNotExists()) for conditions
+
+### Requirement 2
+
+**User Story:** As a presenter creating screenshots, I want each sample method to be concise and focused, so that the code fits well in presentation slides.
+
+#### Acceptance Criteria
+
+1. WHEN a standard operation sample method is written THEN the System SHALL contain between 5 and 20 lines of code
+2. WHEN a transaction or batch operation sample is written THEN the System SHALL show the full verbose Raw SDK implementation without helper methods to maximize the contrast
+3. WHEN sample methods are written THEN the System SHALL avoid TODO comments and placeholder implementations
+4. WHEN sample methods are written THEN the System SHALL use minimal inline comments only where they clarify approach differences
+
+### Requirement 8
+
+**User Story:** As a developer comparing approaches, I want the Raw SDK methods to return actual AWS SDK responses and the Fluent methods to return equivalent domain models, so that I can see full equivalency between approaches.
+
+#### Acceptance Criteria
+
+1. WHEN a Raw SDK method returns a response THEN the System SHALL include manual conversion of the response back to the domain model to demonstrate full equivalency
+2. WHEN a Fluent method returns a result THEN the System SHALL return the same domain model type as the converted Raw SDK response
+
+### Requirement 9
+
+**User Story:** As a developer learning FluentDynamoDb, I want the lambda expression samples to demonstrate the full power of lambda expressions including AttributeExists and AttributeNotExists conditions, so that I understand the type-safe condition capabilities.
+
+#### Acceptance Criteria
+
+1. WHEN a FluentLambda Update method is implemented THEN the System SHALL use Set(x => new UpdateModel { ... }) syntax with lambda expressions
+2. WHEN a FluentLambda method includes a condition THEN the System SHALL use Where(x => x.Property.AttributeExists()) or Where(x => x.Property.AttributeNotExists()) syntax where appropriate
+3. WHEN a FluentLambda method uses entity accessors THEN the System SHALL use express-route methods like PutAsync(entity), GetAsync(key), and DeleteAsync(key) instead of builder chains like Put(entity).PutAsync()
+
+### Requirement 3
+
+**User Story:** As a developer, I want the sample project to compile successfully, so that I can verify the code examples are syntactically correct.
+
+#### Acceptance Criteria
+
+1. WHEN the project is built with `dotnet build` THEN the System SHALL compile without errors
+2. WHEN the project references FluentDynamoDb THEN the System SHALL use the local project reference from the solution
+3. WHEN the project is structured THEN the System SHALL target .NET 8.0 and use nullable reference types
+
+### Requirement 4
+
+**User Story:** As a documentation maintainer, I want a consistent domain model across all samples, so that viewers can follow the examples without confusion.
+
+#### Acceptance Criteria
+
+1. WHEN domain models are defined THEN the System SHALL include Order and OrderLine entities at minimum
+2. WHEN the DynamoDB table schema is represented THEN the System SHALL use a single-table design with pk="ORDER#{OrderId}" and sk="META" or "LINE#{LineId}"
+3. WHEN entity properties are defined THEN the System SHALL include realistic fields without excessive complexity
+4. WHEN the namespace is defined THEN the System SHALL use FluentDynamoDb.OperationSamples consistently
+
+### Requirement 5
+
+**User Story:** As a developer reviewing samples, I want all ten DynamoDB operation types covered, so that I have comprehensive reference material.
+
+#### Acceptance Criteria
+
+1. WHEN sample files are created THEN the System SHALL include GetSamples.cs for GetItem operations
+2. WHEN sample files are created THEN the System SHALL include PutSamples.cs for PutItem operations
+3. WHEN sample files are created THEN the System SHALL include UpdateSamples.cs for UpdateItem operations
+4. WHEN sample files are created THEN the System SHALL include DeleteSamples.cs for DeleteItem operations
+5. WHEN sample files are created THEN the System SHALL include QuerySamples.cs for Query operations
+6. WHEN sample files are created THEN the System SHALL include ScanSamples.cs for Scan operations
+7. WHEN sample files are created THEN the System SHALL include TransactionGetSamples.cs for TransactGetItems operations
+8. WHEN sample files are created THEN the System SHALL include TransactionWriteSamples.cs for TransactWriteItems operations
+9. WHEN sample files are created THEN the System SHALL include BatchGetSamples.cs for BatchGetItem operations
+10. WHEN sample files are created THEN the System SHALL include BatchWriteSamples.cs for BatchWriteItem operations
+
+### Requirement 6
+
+**User Story:** As a presenter, I want the formatted string examples to demonstrate date formatting capabilities, so that viewers understand the full power of the format string approach.
+
+#### Acceptance Criteria
+
+1. WHEN a formatted string sample involves date values THEN the System SHALL demonstrate the {0:o} ISO 8601 format specifier where appropriate
+2. WHEN formatted string samples are written THEN the System SHALL show how placeholders eliminate manual ExpressionAttributeValues management
+
+### Requirement 7
+
+**User Story:** As a developer, I want transaction and batch samples to show multi-entity operations, so that I understand how FluentDynamoDb handles complex scenarios.
+
+#### Acceptance Criteria
+
+1. WHEN transaction write samples are implemented THEN the System SHALL demonstrate operations across multiple entity types in a single transaction
+2. WHEN batch operation samples are implemented THEN the System SHALL demonstrate processing multiple items of different types
+3. WHEN the Raw SDK transaction/batch samples are written THEN the System SHALL avoid helper methods to show the full verbosity contrast
diff --git a/.kiro/specs/operation-samples-showcase/tasks.md b/.kiro/specs/operation-samples-showcase/tasks.md
new file mode 100644
index 0000000..e41a98f
--- /dev/null
+++ b/.kiro/specs/operation-samples-showcase/tasks.md
@@ -0,0 +1,69 @@
+# Implementation Plan
+
+- [x] 1. Set up project structure under examples folder
+ - [x] 1.1 Create examples/OperationSamples/OperationSamples.csproj with .NET 8.0 target, nullable enabled, and project reference to Oproto.FluentDynamoDb
+ - _Requirements: 3.1, 3.2, 3.3_
+ - [x] 1.2 Create Models folder and Samples folder structure under examples/OperationSamples
+ - _Requirements: 4.4_
+
+- [x] 2. Implement domain models
+ - [x] 2.1 Create Order entity with DynamoDbEntity attribute, PartitionKey (Pk), SortKey (Sk), and business properties (OrderId, CustomerId, OrderDate, Status, TotalAmount)
+ - _Requirements: 4.1, 4.2_
+ - [x] 2.2 Create OrderLine entity with DynamoDbEntity attribute, PartitionKey (Pk), SortKey (Sk), and business properties (LineId, ProductId, ProductName, Quantity, UnitPrice)
+ - _Requirements: 4.1, 4.2_
+ - [x] 2.3 Create OrdersTable class extending DynamoDbTableBase with entity accessors for Order and OrderLine
+ - _Requirements: 4.1, 4.2_
+
+- [x] 3. Implement single-item operation samples
+ - [x] 3.1 Create GetSamples.cs with RawSdkGetAsync, FluentManualGetAsync, FluentFormattedGetAsync, FluentLambdaGetAsync methods
+ - _Requirements: 1.1, 1.2, 1.3, 1.4, 1.5, 2.1, 5.1_
+ - [x] 3.2 Create PutSamples.cs with RawSdkPutAsync, FluentManualPutAsync, FluentFormattedPutAsync, FluentLambdaPutAsync methods
+ - _Requirements: 1.1, 1.2, 1.3, 1.4, 1.5, 2.1, 5.2_
+ - [x] 3.3 Create UpdateSamples.cs with RawSdkUpdateAsync, FluentManualUpdateAsync, FluentFormattedUpdateAsync, FluentLambdaUpdateAsync methods demonstrating date formatting with {0:o}
+ - _Requirements: 1.1, 1.2, 1.3, 1.4, 1.5, 2.1, 5.3, 6.1, 6.2_
+ - [x] 3.4 Create DeleteSamples.cs with RawSdkDeleteAsync, FluentManualDeleteAsync, FluentFormattedDeleteAsync, FluentLambdaDeleteAsync methods
+ - _Requirements: 1.1, 1.2, 1.3, 1.4, 1.5, 2.1, 5.4_
+
+- [x] 4. Implement multi-item operation samples
+ - [x] 4.1 Create QuerySamples.cs with RawSdkQueryAsync, FluentManualQueryAsync, FluentFormattedQueryAsync, FluentLambdaQueryAsync methods
+ - _Requirements: 1.1, 1.2, 1.3, 1.4, 1.5, 2.1, 5.5_
+ - [x] 4.2 Create ScanSamples.cs with RawSdkScanAsync, FluentManualScanAsync, FluentFormattedScanAsync, FluentLambdaScanAsync methods
+ - _Requirements: 1.1, 1.2, 1.3, 1.4, 1.5, 2.1, 5.6_
+
+- [x] 5. Implement transaction samples with full verbosity contrast
+ - [x] 5.1 Create TransactionGetSamples.cs with RawSdkTransactionGetAsync (full verbose SDK), FluentManualTransactionGetAsync, FluentFormattedTransactionGetAsync, FluentLambdaTransactionGetAsync methods
+ - _Requirements: 1.1, 1.2, 1.3, 1.4, 1.5, 2.2, 5.7, 7.1_
+ - [x] 5.2 Create TransactionWriteSamples.cs with RawSdkTransactionWriteAsync (full verbose SDK showing Put+Update+Delete), FluentManualTransactionWriteAsync, FluentFormattedTransactionWriteAsync, FluentLambdaTransactionWriteAsync methods demonstrating multi-entity operations
+ - _Requirements: 1.1, 1.2, 1.3, 1.4, 1.5, 2.2, 5.8, 7.1, 7.3_
+
+- [x] 6. Implement batch samples with full verbosity contrast
+ - [x] 6.1 Create BatchGetSamples.cs with RawSdkBatchGetAsync (full verbose SDK), FluentManualBatchGetAsync, FluentFormattedBatchGetAsync, FluentLambdaBatchGetAsync methods demonstrating multiple item types
+ - _Requirements: 1.1, 1.2, 1.3, 1.4, 1.5, 2.2, 5.9, 7.2, 7.3_
+ - [x] 6.2 Create BatchWriteSamples.cs with RawSdkBatchWriteAsync (full verbose SDK), FluentManualBatchWriteAsync, FluentFormattedBatchWriteAsync, FluentLambdaBatchWriteAsync methods demonstrating multiple item types
+ - _Requirements: 1.1, 1.2, 1.3, 1.4, 1.5, 2.2, 5.10, 7.2, 7.3_
+
+- [x] 7. Refine samples for full equivalency and proper lambda expressions
+ - [x] 7.1 Update RawSdk methods to return domain models by manually converting AWS SDK responses
+ - Add manual conversion from AttributeValue dictionaries to domain models
+ - _Requirements: 8.1, 8.2_
+ - [x] 7.2 Create OrderUpdateModel class for lambda expression Set() operations
+ - Add update model with nullable properties for Status, ModifiedAt, TotalAmount
+ - _Requirements: 9.1_
+ - [x] 7.3 Update FluentLambdaUpdateAsync to use Set(x => new OrderUpdateModel { ... }) syntax
+ - Replace format string Set() with lambda expression Set()
+ - _Requirements: 9.1_
+ - [x] 7.4 Update FluentLambdaTransactionWriteAsync to use proper lambda expressions
+ - Use Set(x => new OrderUpdateModel { ... }) for updates
+ - Use Where(x => x.Pk.AttributeNotExists()) and Where(x => x.Pk.AttributeExists()) for conditions
+ - _Requirements: 9.1, 9.2_
+ - [x] 7.5 Verify express-route methods are used in FluentLambda samples
+ - Confirm PutAsync(entity), GetAsync(key), DeleteAsync(key) patterns are used
+ - _Requirements: 9.3_
+
+- [ ] 8. Checkpoint - Verify compilation
+ - Ensure all tests pass, ask the user if questions arise.
+
+- [ ] 9. Write property-based test for sample file structure
+ - [ ] 9.1 Write property test verifying all sample files contain exactly four methods with correct naming patterns
+ - **Property 1: Sample File Method Structure**
+ - **Validates: Requirements 1.1**
diff --git a/examples/OperationSamples/Models/Order.cs b/examples/OperationSamples/Models/Order.cs
new file mode 100644
index 0000000..9c4c664
--- /dev/null
+++ b/examples/OperationSamples/Models/Order.cs
@@ -0,0 +1,88 @@
+using Oproto.FluentDynamoDb.Attributes;
+using Oproto.FluentDynamoDb.Storage;
+
+namespace FluentDynamoDb.OperationSamples.Models;
+
+///
+/// Represents an order in the order management system.
+///
+/// This entity is part of a single-table design where the order header and its
+/// line items are stored with related keys, enabling retrieval of a complete
+/// order with a single Query operation.
+///
+///
+///
+/// Key Design:
+///
+///
+/// - Partition Key (pk): "ORDER#{OrderId}" - groups order with its line items
+/// - Sort Key (sk): "META" - identifies this as the order header
+///
+///
+[DynamoDbEntity]
+[DynamoDbTable("Orders", IsDefault = true)]
+[GenerateEntityProperty(Name = "Orders")]
+public partial class Order : IDynamoDbEntity
+{
+ ///
+ /// Gets or sets the partition key in format "ORDER#{OrderId}".
+ ///
+ [PartitionKey]
+ [DynamoDbAttribute("pk")]
+ public string Pk { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the sort key. For order headers, this is always "META".
+ ///
+ [SortKey]
+ [DynamoDbAttribute("sk")]
+ public string Sk { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the unique order identifier.
+ ///
+ [DynamoDbAttribute("orderId")]
+ public string OrderId { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the customer identifier who placed the order.
+ ///
+ [DynamoDbAttribute("customerId")]
+ public string CustomerId { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the date when the order was placed.
+ ///
+ [DynamoDbAttribute("orderDate")]
+ public DateTime OrderDate { get; set; }
+
+ ///
+ /// Gets or sets the order status (e.g., "Pending", "Shipped", "Delivered").
+ ///
+ [DynamoDbAttribute("orderStatus")]
+ public string Status { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the total amount of the order.
+ ///
+ [DynamoDbAttribute("totalAmount")]
+ public decimal TotalAmount { get; set; }
+
+ ///
+ /// The sort key value for order metadata.
+ ///
+ public const string MetaSk = "META";
+
+ ///
+ /// Creates the partition key for an order.
+ ///
+ /// The order ID.
+ /// The formatted partition key.
+ public static string CreatePk(string orderId) => $"ORDER#{orderId}";
+
+ ///
+ /// Creates the sort key for an order header.
+ ///
+ /// The sort key for order metadata.
+ public static string CreateSk() => MetaSk;
+}
diff --git a/examples/OperationSamples/Models/OrderLine.cs b/examples/OperationSamples/Models/OrderLine.cs
new file mode 100644
index 0000000..f10da44
--- /dev/null
+++ b/examples/OperationSamples/Models/OrderLine.cs
@@ -0,0 +1,97 @@
+using Oproto.FluentDynamoDb.Attributes;
+using Oproto.FluentDynamoDb.Storage;
+
+namespace FluentDynamoDb.OperationSamples.Models;
+
+///
+/// Represents a line item on an order in the order management system.
+///
+/// This entity is part of a single-table design where line items are stored
+/// with sort keys that extend the order's partition key, enabling hierarchical
+/// queries.
+///
+///
+///
+/// Key Design:
+///
+///
+/// - Partition Key (pk): "ORDER#{OrderId}" - same as the parent order
+/// - Sort Key (sk): "LINE#{LineId}" - identifies this as a line item
+///
+///
+/// Hierarchical Query Pattern:
+///
+///
+/// Because all items for an order share the same partition key, a single query
+/// can retrieve both the order header (sk = "META") and all line items
+/// (sk begins_with "LINE#").
+///
+///
+[DynamoDbEntity]
+[DynamoDbTable("Orders")]
+[GenerateEntityProperty(Name = "OrderLines")]
+public partial class OrderLine : IDynamoDbEntity
+{
+ ///
+ /// Gets or sets the partition key in format "ORDER#{OrderId}".
+ ///
+ [PartitionKey]
+ [DynamoDbAttribute("pk")]
+ public string Pk { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the sort key in format "LINE#{LineId}".
+ ///
+ [SortKey]
+ [DynamoDbAttribute("sk")]
+ public string Sk { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the unique line item identifier.
+ ///
+ [DynamoDbAttribute("lineId")]
+ public string LineId { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the product identifier.
+ ///
+ [DynamoDbAttribute("productId")]
+ public string ProductId { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the product name.
+ ///
+ [DynamoDbAttribute("productName")]
+ public string ProductName { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the quantity ordered.
+ ///
+ [DynamoDbAttribute("quantity")]
+ public int Quantity { get; set; }
+
+ ///
+ /// Gets or sets the unit price.
+ ///
+ [DynamoDbAttribute("unitPrice")]
+ public decimal UnitPrice { get; set; }
+
+ ///
+ /// Gets the total amount for this line (Quantity * UnitPrice).
+ ///
+ public decimal Amount => Quantity * UnitPrice;
+
+ ///
+ /// Creates the partition key for an order line.
+ ///
+ /// The order ID.
+ /// The formatted partition key.
+ public static string CreatePk(string orderId) => $"ORDER#{orderId}";
+
+ ///
+ /// Creates the sort key for an order line.
+ ///
+ /// The line ID.
+ /// The formatted sort key.
+ public static string CreateSk(string lineId) => $"LINE#{lineId}";
+}
diff --git a/examples/OperationSamples/Models/OrdersTable.cs b/examples/OperationSamples/Models/OrdersTable.cs
new file mode 100644
index 0000000..539c612
--- /dev/null
+++ b/examples/OperationSamples/Models/OrdersTable.cs
@@ -0,0 +1,50 @@
+using Amazon.DynamoDBv2;
+using Oproto.FluentDynamoDb.Storage;
+
+namespace FluentDynamoDb.OperationSamples.Models;
+
+///
+/// Table class for managing orders and order lines in DynamoDB.
+///
+/// This class demonstrates single-table design where multiple entity types share
+/// the same table, using composite keys to enable efficient access patterns.
+///
+///
+///
+/// Key Design:
+///
+///
+/// All entities use the partition key format "ORDER#{orderId}" to group
+/// all data for an order together. The sort key distinguishes entity types:
+///
+///
+/// - Order: sk = "META"
+/// - OrderLine: sk = "LINE#{lineId}"
+///
+///
+/// Access Patterns:
+///
+///
+/// - Get order: Query pk = "ORDER#{orderId}", sk = "META"
+/// - Get order lines: Query pk = "ORDER#{orderId}", sk begins_with "LINE#"
+/// - Get complete order: Query pk = "ORDER#{orderId}" (returns both order and lines)
+///
+///
+public partial class OrdersTable : DynamoDbTableBase
+{
+ ///
+ /// The name of the DynamoDB table for orders.
+ ///
+ public const string TableName = "Orders";
+
+ ///
+ /// Initializes a new instance of the OrdersTable class.
+ ///
+ /// The DynamoDB client.
+ public OrdersTable(IAmazonDynamoDB client) : base(client, TableName)
+ {
+ }
+
+ // Entity accessors (Orders, OrderLines) are generated by the source generator
+ // based on the [GenerateEntityProperty] attributes on Order and OrderLine entities.
+}
diff --git a/examples/OperationSamples/OperationSamples.csproj b/examples/OperationSamples/OperationSamples.csproj
new file mode 100644
index 0000000..56f0114
--- /dev/null
+++ b/examples/OperationSamples/OperationSamples.csproj
@@ -0,0 +1,18 @@
+
+
+
+ net8.0
+ enable
+ enable
+ 12.0
+ FluentDynamoDb.OperationSamples
+
+
+
+
+
+
+
+
diff --git a/examples/OperationSamples/Samples/.gitkeep b/examples/OperationSamples/Samples/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/examples/OperationSamples/Samples/BatchGetSamples.cs b/examples/OperationSamples/Samples/BatchGetSamples.cs
new file mode 100644
index 0000000..0bf3534
--- /dev/null
+++ b/examples/OperationSamples/Samples/BatchGetSamples.cs
@@ -0,0 +1,147 @@
+using Amazon.DynamoDBv2;
+using Amazon.DynamoDBv2.Model;
+using FluentDynamoDb.OperationSamples.Models;
+using Oproto.FluentDynamoDb;
+using Oproto.FluentDynamoDb.Requests.Extensions;
+
+namespace FluentDynamoDb.OperationSamples.Samples;
+
+///
+/// Demonstrates BatchGetItem operations comparing Raw AWS SDK with FluentDynamoDb approaches.
+/// Each method retrieves an order and multiple line items in a single batch request.
+///
+public static class BatchGetSamples
+{
+ private const string TableName = "Orders";
+
+ ///
+ /// Raw AWS SDK approach - full verbose implementation showing explicit request construction.
+ /// Manually converts response items to domain models for equivalency.
+ ///
+ public static async Task<(Order?, OrderLine?, OrderLine?)> RawSdkBatchGetAsync(
+ IAmazonDynamoDB client, string orderId, string lineId1, string lineId2)
+ {
+ var request = new BatchGetItemRequest
+ {
+ RequestItems = new Dictionary
+ {
+ [TableName] = new KeysAndAttributes
+ {
+ Keys = new List>
+ {
+ new Dictionary
+ {
+ ["pk"] = new AttributeValue { S = $"ORDER#{orderId}" },
+ ["sk"] = new AttributeValue { S = "META" }
+ },
+ new Dictionary
+ {
+ ["pk"] = new AttributeValue { S = $"ORDER#{orderId}" },
+ ["sk"] = new AttributeValue { S = $"LINE#{lineId1}" }
+ },
+ new Dictionary
+ {
+ ["pk"] = new AttributeValue { S = $"ORDER#{orderId}" },
+ ["sk"] = new AttributeValue { S = $"LINE#{lineId2}" }
+ }
+ }
+ }
+ }
+ };
+
+ var response = await client.BatchGetItemAsync(request);
+
+ // Manual conversion of response items to domain models
+ Order? order = null;
+ OrderLine? line1 = null;
+ OrderLine? line2 = null;
+
+ if (response.Responses.TryGetValue(TableName, out var items))
+ {
+ foreach (var item in items)
+ {
+ var sk = item["sk"].S;
+ if (sk == "META")
+ {
+ order = new Order
+ {
+ Pk = item["pk"].S,
+ Sk = item["sk"].S,
+ OrderId = item["orderId"].S,
+ CustomerId = item["customerId"].S,
+ OrderDate = DateTime.Parse(item["orderDate"].S),
+ Status = item["orderStatus"].S,
+ TotalAmount = decimal.Parse(item["totalAmount"].N)
+ };
+ }
+ else if (sk == $"LINE#{lineId1}")
+ {
+ line1 = new OrderLine
+ {
+ Pk = item["pk"].S,
+ Sk = item["sk"].S,
+ LineId = item["lineId"].S,
+ ProductId = item["productId"].S,
+ ProductName = item["productName"].S,
+ Quantity = int.Parse(item["quantity"].N),
+ UnitPrice = decimal.Parse(item["unitPrice"].N)
+ };
+ }
+ else if (sk == $"LINE#{lineId2}")
+ {
+ line2 = new OrderLine
+ {
+ Pk = item["pk"].S,
+ Sk = item["sk"].S,
+ LineId = item["lineId"].S,
+ ProductId = item["productId"].S,
+ ProductName = item["productName"].S,
+ Quantity = int.Parse(item["quantity"].N),
+ UnitPrice = decimal.Parse(item["unitPrice"].N)
+ };
+ }
+ }
+ }
+
+ return (order, line1, line2);
+ }
+
+ ///
+ /// FluentDynamoDb manual builder - uses Get() with explicit key values.
+ ///
+ public static async Task<(Order?, OrderLine?, OrderLine?)> FluentManualBatchGetAsync(
+ OrdersTable table, string orderId, string lineId1, string lineId2)
+ {
+ return await DynamoDbBatch.Get
+ .Add(table.Get().WithKey("pk", $"ORDER#{orderId}", "sk", "META"))
+ .Add(table.Get().WithKey("pk", $"ORDER#{orderId}", "sk", $"LINE#{lineId1}"))
+ .Add(table.Get().WithKey("pk", $"ORDER#{orderId}", "sk", $"LINE#{lineId2}"))
+ .ExecuteAndMapAsync();
+ }
+
+ ///
+ /// FluentDynamoDb formatted string - uses helper methods for key construction.
+ ///
+ public static async Task<(Order?, OrderLine?, OrderLine?)> FluentFormattedBatchGetAsync(
+ OrdersTable table, string orderId, string lineId1, string lineId2)
+ {
+ return await DynamoDbBatch.Get
+ .Add(table.Get().WithKey("pk", Order.CreatePk(orderId), "sk", Order.CreateSk()))
+ .Add(table.Get().WithKey("pk", OrderLine.CreatePk(orderId), "sk", OrderLine.CreateSk(lineId1)))
+ .Add(table.Get().WithKey("pk", OrderLine.CreatePk(orderId), "sk", OrderLine.CreateSk(lineId2)))
+ .ExecuteAndMapAsync();
+ }
+
+ ///
+ /// FluentDynamoDb lambda expression - uses entity accessors with strongly-typed keys.
+ ///
+ public static async Task<(Order?, OrderLine?, OrderLine?)> FluentLambdaBatchGetAsync(
+ OrdersTable table, string orderId, string lineId1, string lineId2)
+ {
+ return await DynamoDbBatch.Get
+ .Add(table.Orders.Get(Order.CreatePk(orderId), Order.CreateSk()))
+ .Add(table.OrderLines.Get(OrderLine.CreatePk(orderId), OrderLine.CreateSk(lineId1)))
+ .Add(table.OrderLines.Get(OrderLine.CreatePk(orderId), OrderLine.CreateSk(lineId2)))
+ .ExecuteAndMapAsync();
+ }
+}
diff --git a/examples/OperationSamples/Samples/BatchWriteSamples.cs b/examples/OperationSamples/Samples/BatchWriteSamples.cs
new file mode 100644
index 0000000..426f108
--- /dev/null
+++ b/examples/OperationSamples/Samples/BatchWriteSamples.cs
@@ -0,0 +1,162 @@
+using Amazon.DynamoDBv2;
+using Amazon.DynamoDBv2.Model;
+using FluentDynamoDb.OperationSamples.Models;
+using Oproto.FluentDynamoDb;
+using Oproto.FluentDynamoDb.Requests.Extensions;
+
+namespace FluentDynamoDb.OperationSamples.Samples;
+
+///
+/// Demonstrates BatchWriteItem operations comparing Raw AWS SDK with FluentDynamoDb approaches.
+/// Each method performs bulk put and delete operations across Order and OrderLine entities.
+/// Note: Batch operations do not support condition expressions.
+///
+public static class BatchWriteSamples
+{
+ private const string TableName = "Orders";
+
+ ///
+ /// Raw AWS SDK approach - full verbose implementation showing Put+Delete in one batch.
+ /// This demonstrates the extreme verbosity required without any abstraction layer.
+ ///
+ public static async Task RawSdkBatchWriteAsync(
+ IAmazonDynamoDB client,
+ Order newOrder,
+ OrderLine newLine1,
+ OrderLine newLine2,
+ string deleteOrderId,
+ string deleteLineId)
+ {
+ var request = new BatchWriteItemRequest
+ {
+ RequestItems = new Dictionary>
+ {
+ [TableName] = new List
+ {
+ // Put: Add a new order
+ new WriteRequest
+ {
+ PutRequest = new PutRequest
+ {
+ Item = new Dictionary
+ {
+ ["pk"] = new AttributeValue { S = newOrder.Pk },
+ ["sk"] = new AttributeValue { S = newOrder.Sk },
+ ["orderId"] = new AttributeValue { S = newOrder.OrderId },
+ ["customerId"] = new AttributeValue { S = newOrder.CustomerId },
+ ["orderDate"] = new AttributeValue { S = newOrder.OrderDate.ToString("o") },
+ ["orderStatus"] = new AttributeValue { S = newOrder.Status },
+ ["totalAmount"] = new AttributeValue { N = newOrder.TotalAmount.ToString() }
+ }
+ }
+ },
+ // Put: Add first order line
+ new WriteRequest
+ {
+ PutRequest = new PutRequest
+ {
+ Item = new Dictionary
+ {
+ ["pk"] = new AttributeValue { S = newLine1.Pk },
+ ["sk"] = new AttributeValue { S = newLine1.Sk },
+ ["lineId"] = new AttributeValue { S = newLine1.LineId },
+ ["productId"] = new AttributeValue { S = newLine1.ProductId },
+ ["productName"] = new AttributeValue { S = newLine1.ProductName },
+ ["quantity"] = new AttributeValue { N = newLine1.Quantity.ToString() },
+ ["unitPrice"] = new AttributeValue { N = newLine1.UnitPrice.ToString() }
+ }
+ }
+ },
+ // Put: Add second order line
+ new WriteRequest
+ {
+ PutRequest = new PutRequest
+ {
+ Item = new Dictionary
+ {
+ ["pk"] = new AttributeValue { S = newLine2.Pk },
+ ["sk"] = new AttributeValue { S = newLine2.Sk },
+ ["lineId"] = new AttributeValue { S = newLine2.LineId },
+ ["productId"] = new AttributeValue { S = newLine2.ProductId },
+ ["productName"] = new AttributeValue { S = newLine2.ProductName },
+ ["quantity"] = new AttributeValue { N = newLine2.Quantity.ToString() },
+ ["unitPrice"] = new AttributeValue { N = newLine2.UnitPrice.ToString() }
+ }
+ }
+ },
+ // Delete: Remove an old order line
+ new WriteRequest
+ {
+ DeleteRequest = new DeleteRequest
+ {
+ Key = new Dictionary
+ {
+ ["pk"] = new AttributeValue { S = $"ORDER#{deleteOrderId}" },
+ ["sk"] = new AttributeValue { S = $"LINE#{deleteLineId}" }
+ }
+ }
+ }
+ }
+ }
+ };
+
+ return await client.BatchWriteItemAsync(request);
+ }
+
+ ///
+ /// FluentDynamoDb manual builder - uses explicit WithItem() and WithKey() methods.
+ ///
+ public static async Task FluentManualBatchWriteAsync(
+ OrdersTable table,
+ Order newOrder,
+ OrderLine newLine1,
+ OrderLine newLine2,
+ string deleteOrderId,
+ string deleteLineId)
+ {
+ return await DynamoDbBatch.Write
+ .Add(table.Put().WithItem(newOrder))
+ .Add(table.Put().WithItem(newLine1))
+ .Add(table.Put().WithItem(newLine2))
+ .Add(table.Delete().WithKey("pk", $"ORDER#{deleteOrderId}", "sk", $"LINE#{deleteLineId}"))
+ .ExecuteAsync();
+ }
+
+ ///
+ /// FluentDynamoDb formatted string - uses helper methods for key construction.
+ ///
+ public static async Task FluentFormattedBatchWriteAsync(
+ OrdersTable table,
+ Order newOrder,
+ OrderLine newLine1,
+ OrderLine newLine2,
+ string deleteOrderId,
+ string deleteLineId)
+ {
+ return await DynamoDbBatch.Write
+ .Add(table.Put().WithItem(newOrder))
+ .Add(table.Put().WithItem(newLine1))
+ .Add(table.Put().WithItem(newLine2))
+ .Add(table.Delete().WithKey("pk", OrderLine.CreatePk(deleteOrderId), "sk", OrderLine.CreateSk(deleteLineId)))
+ .ExecuteAsync();
+ }
+
+ ///
+ /// FluentDynamoDb lambda expression - uses entity accessors with strongly-typed operations.
+ ///
+ public static async Task FluentLambdaBatchWriteAsync(
+ OrdersTable table,
+ Order newOrder,
+ OrderLine newLine1,
+ OrderLine newLine2,
+ string deleteOrderId,
+ string deleteLineId)
+ {
+ return await DynamoDbBatch.Write
+ .Add(table.Orders.Put(newOrder))
+ .Add(table.OrderLines.Put(newLine1))
+ .Add(table.OrderLines.Put(newLine2))
+ .Add(table.OrderLines.Delete(OrderLine.CreatePk(deleteOrderId), OrderLine.CreateSk(deleteLineId)))
+ .ExecuteAsync();
+ }
+}
diff --git a/examples/OperationSamples/Samples/DeleteSamples.cs b/examples/OperationSamples/Samples/DeleteSamples.cs
new file mode 100644
index 0000000..7a4eecc
--- /dev/null
+++ b/examples/OperationSamples/Samples/DeleteSamples.cs
@@ -0,0 +1,78 @@
+using Amazon.DynamoDBv2;
+using Amazon.DynamoDBv2.Model;
+using FluentDynamoDb.OperationSamples.Models;
+using Oproto.FluentDynamoDb.Requests.Extensions;
+
+namespace FluentDynamoDb.OperationSamples.Samples;
+
+///
+/// Demonstrates DeleteItem operations comparing Raw AWS SDK with FluentDynamoDb approaches.
+/// Each method deletes an order by its composite key (pk + sk).
+///
+public static class DeleteSamples
+{
+ private const string TableName = "Orders";
+
+ ///
+ /// Raw AWS SDK approach - explicit AttributeValue dictionaries for key specification.
+ /// Uses ReturnValues to get the deleted item for equivalency demonstration.
+ ///
+ public static async Task RawSdkDeleteAsync(IAmazonDynamoDB client, string orderId)
+ {
+ var request = new DeleteItemRequest
+ {
+ TableName = TableName,
+ Key = new Dictionary
+ {
+ ["pk"] = new AttributeValue { S = $"ORDER#{orderId}" },
+ ["sk"] = new AttributeValue { S = "META" }
+ },
+ ReturnValues = ReturnValue.ALL_OLD
+ };
+
+ var response = await client.DeleteItemAsync(request);
+
+ if (response.Attributes == null || response.Attributes.Count == 0)
+ return null;
+
+ // Manual conversion of deleted item to domain model
+ return new Order
+ {
+ Pk = response.Attributes["pk"].S,
+ Sk = response.Attributes["sk"].S,
+ OrderId = response.Attributes["orderId"].S,
+ CustomerId = response.Attributes["customerId"].S,
+ OrderDate = DateTime.Parse(response.Attributes["orderDate"].S),
+ Status = response.Attributes["orderStatus"].S,
+ TotalAmount = decimal.Parse(response.Attributes["totalAmount"].N)
+ };
+ }
+
+ ///
+ /// FluentDynamoDb manual builder - uses WithKey() with explicit string values.
+ ///
+ public static async Task FluentManualDeleteAsync(OrdersTable table, string orderId)
+ {
+ await table.Delete()
+ .WithKey("pk", $"ORDER#{orderId}", "sk", "META")
+ .DeleteAsync();
+ }
+
+ ///
+ /// FluentDynamoDb formatted string - uses constant for sort key value.
+ ///
+ public static async Task FluentFormattedDeleteAsync(OrdersTable table, string orderId)
+ {
+ await table.Delete()
+ .WithKey("pk", $"ORDER#{orderId}", "sk", Order.MetaSk)
+ .DeleteAsync();
+ }
+
+ ///
+ /// FluentDynamoDb lambda expression - uses entity accessor with key parameters.
+ ///
+ public static async Task FluentLambdaDeleteAsync(OrdersTable table, string orderId)
+ {
+ await table.Orders.DeleteAsync(Order.CreatePk(orderId), Order.CreateSk());
+ }
+}
diff --git a/examples/OperationSamples/Samples/GetSamples.cs b/examples/OperationSamples/Samples/GetSamples.cs
new file mode 100644
index 0000000..be3e34e
--- /dev/null
+++ b/examples/OperationSamples/Samples/GetSamples.cs
@@ -0,0 +1,76 @@
+using Amazon.DynamoDBv2;
+using Amazon.DynamoDBv2.Model;
+using FluentDynamoDb.OperationSamples.Models;
+using Oproto.FluentDynamoDb.Requests.Extensions;
+
+namespace FluentDynamoDb.OperationSamples.Samples;
+
+///
+/// Demonstrates GetItem operations comparing Raw AWS SDK with FluentDynamoDb approaches.
+/// Each method retrieves an order by its composite key (pk + sk).
+///
+public static class GetSamples
+{
+ private const string TableName = "Orders";
+
+ ///
+ /// Raw AWS SDK approach - explicit AttributeValue dictionaries and manual response conversion.
+ ///
+ public static async Task RawSdkGetAsync(IAmazonDynamoDB client, string orderId)
+ {
+ var request = new GetItemRequest
+ {
+ TableName = TableName,
+ Key = new Dictionary
+ {
+ ["pk"] = new AttributeValue { S = $"ORDER#{orderId}" },
+ ["sk"] = new AttributeValue { S = "META" }
+ }
+ };
+
+ var response = await client.GetItemAsync(request);
+
+ if (response.Item == null || response.Item.Count == 0)
+ return null;
+
+ // Manual conversion to domain model
+ return new Order
+ {
+ Pk = response.Item["pk"].S,
+ Sk = response.Item["sk"].S,
+ OrderId = response.Item["orderId"].S,
+ CustomerId = response.Item["customerId"].S,
+ OrderDate = DateTime.Parse(response.Item["orderDate"].S),
+ Status = response.Item["orderStatus"].S,
+ TotalAmount = decimal.Parse(response.Item["totalAmount"].N)
+ };
+ }
+
+ ///
+ /// FluentDynamoDb manual builder - uses WithKey() with explicit string values.
+ ///
+ public static async Task FluentManualGetAsync(OrdersTable table, string orderId)
+ {
+ return await table.Get()
+ .WithKey("pk", $"ORDER#{orderId}", "sk", "META")
+ .GetItemAsync();
+ }
+
+ ///
+ /// FluentDynamoDb formatted string - uses constants for key values.
+ ///
+ public static async Task FluentFormattedGetAsync(OrdersTable table, string orderId)
+ {
+ return await table.Get()
+ .WithKey("pk", $"ORDER#{orderId}", "sk", Order.MetaSk)
+ .GetItemAsync();
+ }
+
+ ///
+ /// FluentDynamoDb lambda expression - uses strongly-typed helper methods for keys.
+ ///
+ public static async Task FluentLambdaGetAsync(OrdersTable table, string orderId)
+ {
+ return await table.Orders.GetAsync(Order.CreatePk(orderId), Order.CreateSk());
+ }
+}
diff --git a/examples/OperationSamples/Samples/PutSamples.cs b/examples/OperationSamples/Samples/PutSamples.cs
new file mode 100644
index 0000000..e6f3934
--- /dev/null
+++ b/examples/OperationSamples/Samples/PutSamples.cs
@@ -0,0 +1,70 @@
+using Amazon.DynamoDBv2;
+using Amazon.DynamoDBv2.Model;
+using FluentDynamoDb.OperationSamples.Models;
+using Oproto.FluentDynamoDb.Requests.Extensions;
+
+namespace FluentDynamoDb.OperationSamples.Samples;
+
+///
+/// Demonstrates PutItem operations comparing Raw AWS SDK with FluentDynamoDb approaches.
+/// Each method creates or replaces an order in the table.
+///
+public static class PutSamples
+{
+ private const string TableName = "Orders";
+
+ ///
+ /// Raw AWS SDK approach - explicit AttributeValue dictionaries for all fields.
+ /// Returns the order that was put (for equivalency with Fluent methods).
+ ///
+ public static async Task RawSdkPutAsync(IAmazonDynamoDB client, Order order)
+ {
+ var request = new PutItemRequest
+ {
+ TableName = TableName,
+ Item = new Dictionary
+ {
+ ["pk"] = new AttributeValue { S = order.Pk },
+ ["sk"] = new AttributeValue { S = order.Sk },
+ ["orderId"] = new AttributeValue { S = order.OrderId },
+ ["customerId"] = new AttributeValue { S = order.CustomerId },
+ ["orderDate"] = new AttributeValue { S = order.OrderDate.ToString("o") },
+ ["orderStatus"] = new AttributeValue { S = order.Status },
+ ["totalAmount"] = new AttributeValue { N = order.TotalAmount.ToString() }
+ }
+ };
+
+ await client.PutItemAsync(request);
+
+ // Return the order for equivalency (Put doesn't return item by default)
+ return order;
+ }
+
+ ///
+ /// FluentDynamoDb manual builder - uses WithItem() with entity mapping.
+ ///
+ public static async Task FluentManualPutAsync(OrdersTable table, Order order)
+ {
+ await table.Put()
+ .WithItem(order)
+ .PutAsync();
+ }
+
+ ///
+ /// FluentDynamoDb formatted string - same as manual for Put operations.
+ ///
+ public static async Task FluentFormattedPutAsync(OrdersTable table, Order order)
+ {
+ await table.Put()
+ .WithItem(order)
+ .PutAsync();
+ }
+
+ ///
+ /// FluentDynamoDb lambda expression - uses entity accessor with automatic mapping.
+ ///
+ public static async Task FluentLambdaPutAsync(OrdersTable table, Order order)
+ {
+ await table.Orders.PutAsync(order);
+ }
+}
diff --git a/examples/OperationSamples/Samples/QuerySamples.cs b/examples/OperationSamples/Samples/QuerySamples.cs
new file mode 100644
index 0000000..e751bfd
--- /dev/null
+++ b/examples/OperationSamples/Samples/QuerySamples.cs
@@ -0,0 +1,79 @@
+using Amazon.DynamoDBv2;
+using Amazon.DynamoDBv2.Model;
+using FluentDynamoDb.OperationSamples.Models;
+using Oproto.FluentDynamoDb.Requests.Extensions;
+
+namespace FluentDynamoDb.OperationSamples.Samples;
+
+///
+/// Demonstrates Query operations comparing Raw AWS SDK with FluentDynamoDb approaches.
+/// Each method queries order lines for a specific order using the partition key.
+///
+public static class QuerySamples
+{
+ private const string TableName = "Orders";
+
+ ///
+ /// Raw AWS SDK approach - explicit KeyConditionExpression and AttributeValue dictionaries.
+ /// Manually converts response items to domain models for equivalency.
+ ///
+ public static async Task> RawSdkQueryAsync(IAmazonDynamoDB client, string orderId)
+ {
+ var request = new QueryRequest
+ {
+ TableName = TableName,
+ KeyConditionExpression = "pk = :pk AND begins_with(sk, :skPrefix)",
+ ExpressionAttributeValues = new Dictionary
+ {
+ [":pk"] = new AttributeValue { S = $"ORDER#{orderId}" },
+ [":skPrefix"] = new AttributeValue { S = "LINE#" }
+ }
+ };
+
+ var response = await client.QueryAsync(request);
+
+ // Manual conversion of items to domain models
+ return response.Items.Select(item => new OrderLine
+ {
+ Pk = item["pk"].S,
+ Sk = item["sk"].S,
+ LineId = item["lineId"].S,
+ ProductId = item["productId"].S,
+ ProductName = item["productName"].S,
+ Quantity = int.Parse(item["quantity"].N),
+ UnitPrice = decimal.Parse(item["unitPrice"].N)
+ }).ToList();
+ }
+
+ ///
+ /// FluentDynamoDb manual builder - uses Where() with WithValue() methods.
+ ///
+ public static async Task> FluentManualQueryAsync(OrdersTable table, string orderId)
+ {
+ return await table.Query()
+ .Where("pk = :pk AND begins_with(sk, :skPrefix)")
+ .WithValue(":pk", $"ORDER#{orderId}")
+ .WithValue(":skPrefix", "LINE#")
+ .ToListAsync();
+ }
+
+ ///
+ /// FluentDynamoDb formatted string - uses positional placeholders for values.
+ ///
+ public static async Task> FluentFormattedQueryAsync(OrdersTable table, string orderId)
+ {
+ return await table.Query()
+ .Where("pk = {0} AND begins_with(sk, {1})", OrderLine.CreatePk(orderId), "LINE#")
+ .ToListAsync();
+ }
+
+ ///
+ /// FluentDynamoDb lambda expression - uses entity accessor with strongly-typed expressions.
+ ///
+ public static async Task> FluentLambdaQueryAsync(OrdersTable table, string orderId)
+ {
+ return await table.OrderLines.Query()
+ .Where(x => x.Pk == OrderLine.CreatePk(orderId) && x.Sk.StartsWith("LINE#"))
+ .ToListAsync();
+ }
+}
diff --git a/examples/OperationSamples/Samples/ScanSamples.cs b/examples/OperationSamples/Samples/ScanSamples.cs
new file mode 100644
index 0000000..654c030
--- /dev/null
+++ b/examples/OperationSamples/Samples/ScanSamples.cs
@@ -0,0 +1,85 @@
+using Amazon.DynamoDBv2;
+using Amazon.DynamoDBv2.Model;
+using FluentDynamoDb.OperationSamples.Models;
+using Oproto.FluentDynamoDb.Requests.Extensions;
+
+namespace FluentDynamoDb.OperationSamples.Samples;
+
+///
+/// Demonstrates Scan operations comparing Raw AWS SDK with FluentDynamoDb approaches.
+/// Each method scans for orders with a specific status filter.
+///
+public static class ScanSamples
+{
+ private const string TableName = "Orders";
+
+ ///
+ /// Raw AWS SDK approach - explicit FilterExpression and AttributeValue dictionaries.
+ /// Manually converts response items to domain models for equivalency.
+ ///
+ public static async Task> RawSdkScanAsync(IAmazonDynamoDB client, string status)
+ {
+ var request = new ScanRequest
+ {
+ TableName = TableName,
+ FilterExpression = "#status = :status AND sk = :sk",
+ ExpressionAttributeNames = new Dictionary
+ {
+ ["#status"] = "orderStatus"
+ },
+ ExpressionAttributeValues = new Dictionary
+ {
+ [":status"] = new AttributeValue { S = status },
+ [":sk"] = new AttributeValue { S = "META" }
+ }
+ };
+
+ var response = await client.ScanAsync(request);
+
+ // Manual conversion of items to domain models
+ return response.Items.Select(item => new Order
+ {
+ Pk = item["pk"].S,
+ Sk = item["sk"].S,
+ OrderId = item["orderId"].S,
+ CustomerId = item["customerId"].S,
+ OrderDate = DateTime.Parse(item["orderDate"].S),
+ Status = item["orderStatus"].S,
+ TotalAmount = decimal.Parse(item["totalAmount"].N)
+ }).ToList();
+ }
+
+ ///
+ /// FluentDynamoDb manual builder - uses WithFilter() with WithAttribute() and WithValue() methods.
+ ///
+ public static async Task> FluentManualScanAsync(OrdersTable table, string status)
+ {
+ return await table.Scan()
+ .WithFilter("#status = :status AND sk = :sk")
+ .WithAttribute("#status", "orderStatus")
+ .WithValue(":status", status)
+ .WithValue(":sk", Order.MetaSk)
+ .ToListAsync();
+ }
+
+ ///
+ /// FluentDynamoDb formatted string - uses positional placeholders for values.
+ ///
+ public static async Task> FluentFormattedScanAsync(OrdersTable table, string status)
+ {
+ return await table.Scan()
+ .WithFilter("#status = {0} AND sk = {1}", status, Order.MetaSk)
+ .WithAttribute("#status", "orderStatus")
+ .ToListAsync();
+ }
+
+ ///
+ /// FluentDynamoDb lambda expression - uses strongly-typed filter expressions.
+ ///
+ public static async Task> FluentLambdaScanAsync(OrdersTable table, string status)
+ {
+ return await table.Scan()
+ .WithFilter(x => x.Status == status && x.Sk == Order.MetaSk)
+ .ToListAsync();
+ }
+}
diff --git a/examples/OperationSamples/Samples/TransactionGetSamples.cs b/examples/OperationSamples/Samples/TransactionGetSamples.cs
new file mode 100644
index 0000000..8515069
--- /dev/null
+++ b/examples/OperationSamples/Samples/TransactionGetSamples.cs
@@ -0,0 +1,129 @@
+using Amazon.DynamoDBv2;
+using Amazon.DynamoDBv2.Model;
+using FluentDynamoDb.OperationSamples.Models;
+using Oproto.FluentDynamoDb;
+using Oproto.FluentDynamoDb.Requests.Extensions;
+
+namespace FluentDynamoDb.OperationSamples.Samples;
+
+///
+/// Demonstrates TransactGetItems operations comparing Raw AWS SDK with FluentDynamoDb approaches.
+/// Each method retrieves an order and its line item atomically with snapshot isolation.
+///
+public static class TransactionGetSamples
+{
+ private const string TableName = "Orders";
+
+ ///
+ /// Raw AWS SDK approach - full verbose implementation showing explicit request construction.
+ /// Manually converts response items to domain models for equivalency.
+ ///
+ public static async Task<(Order?, OrderLine?)> RawSdkTransactionGetAsync(
+ IAmazonDynamoDB client, string orderId, string lineId)
+ {
+ var request = new TransactGetItemsRequest
+ {
+ TransactItems = new List
+ {
+ new TransactGetItem
+ {
+ Get = new Get
+ {
+ TableName = TableName,
+ Key = new Dictionary
+ {
+ ["pk"] = new AttributeValue { S = $"ORDER#{orderId}" },
+ ["sk"] = new AttributeValue { S = "META" }
+ }
+ }
+ },
+ new TransactGetItem
+ {
+ Get = new Get
+ {
+ TableName = TableName,
+ Key = new Dictionary
+ {
+ ["pk"] = new AttributeValue { S = $"ORDER#{orderId}" },
+ ["sk"] = new AttributeValue { S = $"LINE#{lineId}" }
+ }
+ }
+ }
+ }
+ };
+
+ var response = await client.TransactGetItemsAsync(request);
+
+ // Manual conversion of response items to domain models
+ Order? order = null;
+ OrderLine? orderLine = null;
+
+ if (response.Responses.Count > 0 && response.Responses[0].Item?.Count > 0)
+ {
+ var item = response.Responses[0].Item;
+ order = new Order
+ {
+ Pk = item["pk"].S,
+ Sk = item["sk"].S,
+ OrderId = item["orderId"].S,
+ CustomerId = item["customerId"].S,
+ OrderDate = DateTime.Parse(item["orderDate"].S),
+ Status = item["orderStatus"].S,
+ TotalAmount = decimal.Parse(item["totalAmount"].N)
+ };
+ }
+
+ if (response.Responses.Count > 1 && response.Responses[1].Item?.Count > 0)
+ {
+ var item = response.Responses[1].Item;
+ orderLine = new OrderLine
+ {
+ Pk = item["pk"].S,
+ Sk = item["sk"].S,
+ LineId = item["lineId"].S,
+ ProductId = item["productId"].S,
+ ProductName = item["productName"].S,
+ Quantity = int.Parse(item["quantity"].N),
+ UnitPrice = decimal.Parse(item["unitPrice"].N)
+ };
+ }
+
+ return (order, orderLine);
+ }
+
+ ///
+ /// FluentDynamoDb manual builder - uses Get() with explicit key values.
+ ///
+ public static async Task<(Order?, OrderLine?)> FluentManualTransactionGetAsync(
+ OrdersTable table, string orderId, string lineId)
+ {
+ return await DynamoDbTransactions.Get
+ .Add(table.Get().WithKey("pk", $"ORDER#{orderId}", "sk", "META"))
+ .Add(table.Get().WithKey("pk", $"ORDER#{orderId}", "sk", $"LINE#{lineId}"))
+ .ExecuteAndMapAsync();
+ }
+
+ ///
+ /// FluentDynamoDb formatted string - uses helper methods for key construction.
+ ///
+ public static async Task<(Order?, OrderLine?)> FluentFormattedTransactionGetAsync(
+ OrdersTable table, string orderId, string lineId)
+ {
+ return await DynamoDbTransactions.Get
+ .Add(table.Get().WithKey("pk", Order.CreatePk(orderId), "sk", Order.CreateSk()))
+ .Add(table.Get().WithKey("pk", OrderLine.CreatePk(orderId), "sk", OrderLine.CreateSk(lineId)))
+ .ExecuteAndMapAsync();
+ }
+
+ ///
+ /// FluentDynamoDb lambda expression - uses entity accessors with strongly-typed keys.
+ ///
+ public static async Task<(Order?, OrderLine?)> FluentLambdaTransactionGetAsync(
+ OrdersTable table, string orderId, string lineId)
+ {
+ return await DynamoDbTransactions.Get
+ .Add(table.Orders.Get(Order.CreatePk(orderId), Order.CreateSk()))
+ .Add(table.OrderLines.Get(OrderLine.CreatePk(orderId), OrderLine.CreateSk(lineId)))
+ .ExecuteAndMapAsync();
+ }
+}
diff --git a/examples/OperationSamples/Samples/TransactionWriteSamples.cs b/examples/OperationSamples/Samples/TransactionWriteSamples.cs
new file mode 100644
index 0000000..d779c80
--- /dev/null
+++ b/examples/OperationSamples/Samples/TransactionWriteSamples.cs
@@ -0,0 +1,166 @@
+using Amazon.DynamoDBv2;
+using Amazon.DynamoDBv2.Model;
+using FluentDynamoDb.OperationSamples.Models;
+using Oproto.FluentDynamoDb;
+using Oproto.FluentDynamoDb.Requests.Extensions;
+
+namespace FluentDynamoDb.OperationSamples.Samples;
+
+///
+/// Demonstrates TransactWriteItems operations comparing Raw AWS SDK with FluentDynamoDb approaches.
+/// Each method performs atomic Put+Update+Delete operations across Order and OrderLine entities.
+///
+public static class TransactionWriteSamples
+{
+ private const string TableName = "Orders";
+
+ ///
+ /// Raw AWS SDK approach - full verbose implementation showing Put+Update+Delete in one transaction.
+ /// This demonstrates the extreme verbosity required without any abstraction layer.
+ ///
+ public static async Task RawSdkTransactionWriteAsync(
+ IAmazonDynamoDB client,
+ OrderLine newLine,
+ string orderId,
+ decimal newTotal,
+ string deleteLineId)
+ {
+ var request = new TransactWriteItemsRequest
+ {
+ TransactItems = new List
+ {
+ // Put: Add a new order line
+ new TransactWriteItem
+ {
+ Put = new Put
+ {
+ TableName = TableName,
+ Item = new Dictionary
+ {
+ ["pk"] = new AttributeValue { S = newLine.Pk },
+ ["sk"] = new AttributeValue { S = newLine.Sk },
+ ["lineId"] = new AttributeValue { S = newLine.LineId },
+ ["productId"] = new AttributeValue { S = newLine.ProductId },
+ ["productName"] = new AttributeValue { S = newLine.ProductName },
+ ["quantity"] = new AttributeValue { N = newLine.Quantity.ToString() },
+ ["unitPrice"] = new AttributeValue { N = newLine.UnitPrice.ToString() }
+ },
+ ConditionExpression = "attribute_not_exists(pk)"
+ }
+ },
+ // Update: Update the order total
+ new TransactWriteItem
+ {
+ Update = new Update
+ {
+ TableName = TableName,
+ Key = new Dictionary
+ {
+ ["pk"] = new AttributeValue { S = $"ORDER#{orderId}" },
+ ["sk"] = new AttributeValue { S = "META" }
+ },
+ UpdateExpression = "SET #total = :total",
+ ExpressionAttributeNames = new Dictionary
+ {
+ ["#total"] = "totalAmount"
+ },
+ ExpressionAttributeValues = new Dictionary
+ {
+ [":total"] = new AttributeValue { N = newTotal.ToString() }
+ },
+ ConditionExpression = "attribute_exists(pk)"
+ }
+ },
+ // Delete: Remove an old order line
+ new TransactWriteItem
+ {
+ Delete = new Delete
+ {
+ TableName = TableName,
+ Key = new Dictionary
+ {
+ ["pk"] = new AttributeValue { S = $"ORDER#{orderId}" },
+ ["sk"] = new AttributeValue { S = $"LINE#{deleteLineId}" }
+ },
+ ConditionExpression = "attribute_exists(pk)"
+ }
+ }
+ }
+ };
+
+ return await client.TransactWriteItemsAsync(request);
+ }
+
+ ///
+ /// FluentDynamoDb manual builder - uses explicit WithKey(), WithItem(), and expression strings.
+ ///
+ public static async Task FluentManualTransactionWriteAsync(
+ OrdersTable table,
+ OrderLine newLine,
+ string orderId,
+ decimal newTotal,
+ string deleteLineId)
+ {
+ await DynamoDbTransactions.Write
+ .Add(table.Put()
+ .WithItem(newLine)
+ .Where("attribute_not_exists(pk)"))
+ .Add(table.Update()
+ .WithKey("pk", $"ORDER#{orderId}", "sk", "META")
+ .Set("SET #total = :total")
+ .WithAttribute("#total", "totalAmount")
+ .WithValue(":total", newTotal)
+ .Where("attribute_exists(pk)"))
+ .Add(table.Delete()
+ .WithKey("pk", $"ORDER#{orderId}", "sk", $"LINE#{deleteLineId}")
+ .Where("attribute_exists(pk)"))
+ .ExecuteAsync();
+ }
+
+ ///
+ /// FluentDynamoDb formatted string - uses placeholders and helper methods for keys.
+ ///
+ public static async Task FluentFormattedTransactionWriteAsync(
+ OrdersTable table,
+ OrderLine newLine,
+ string orderId,
+ decimal newTotal,
+ string deleteLineId)
+ {
+ await DynamoDbTransactions.Write
+ .Add(table.Put()
+ .WithItem(newLine)
+ .Where("attribute_not_exists(pk)"))
+ .Add(table.Update()
+ .WithKey("pk", Order.CreatePk(orderId), "sk", Order.CreateSk())
+ .Set("SET #total = {0}", newTotal)
+ .WithAttribute("#total", "totalAmount")
+ .Where("attribute_exists(pk)"))
+ .Add(table.Delete()
+ .WithKey("pk", OrderLine.CreatePk(orderId), "sk", OrderLine.CreateSk(deleteLineId))
+ .Where("attribute_exists(pk)"))
+ .ExecuteAsync();
+ }
+
+ ///
+ /// FluentDynamoDb lambda expression - uses entity accessors with strongly-typed Set().
+ /// Note: Transaction builders use format strings for Where() conditions.
+ ///
+ public static async Task FluentLambdaTransactionWriteAsync(
+ OrdersTable table,
+ OrderLine newLine,
+ string orderId,
+ decimal newTotal,
+ string deleteLineId)
+ {
+ await DynamoDbTransactions.Write
+ .Add(table.OrderLines.Put(newLine)
+ .Where("attribute_not_exists(pk)"))
+ .Add(table.Orders.Update(Order.CreatePk(orderId), Order.CreateSk())
+ .Set(x => new OrderUpdateModel { TotalAmount = newTotal })
+ .Where("attribute_exists(pk)"))
+ .Add(table.OrderLines.Delete(OrderLine.CreatePk(orderId), OrderLine.CreateSk(deleteLineId))
+ .Where("attribute_exists(pk)"))
+ .ExecuteAsync();
+ }
+}
diff --git a/examples/OperationSamples/Samples/UpdateSamples.cs b/examples/OperationSamples/Samples/UpdateSamples.cs
new file mode 100644
index 0000000..3fa4198
--- /dev/null
+++ b/examples/OperationSamples/Samples/UpdateSamples.cs
@@ -0,0 +1,107 @@
+using Amazon.DynamoDBv2;
+using Amazon.DynamoDBv2.Model;
+using FluentDynamoDb.OperationSamples.Models;
+using Oproto.FluentDynamoDb.Requests.Extensions;
+
+namespace FluentDynamoDb.OperationSamples.Samples;
+
+///
+/// Demonstrates UpdateItem operations comparing Raw AWS SDK with FluentDynamoDb approaches.
+/// Each method updates an order's status and modified date.
+///
+public static class UpdateSamples
+{
+ private const string TableName = "Orders";
+
+ ///
+ /// Raw AWS SDK approach - explicit expression strings and AttributeValue dictionaries.
+ /// Uses ReturnValues to get the updated item for equivalency demonstration.
+ ///
+ public static async Task RawSdkUpdateAsync(
+ IAmazonDynamoDB client, string orderId, string newStatus, DateTime modifiedAt)
+ {
+ var request = new UpdateItemRequest
+ {
+ TableName = TableName,
+ Key = new Dictionary
+ {
+ ["pk"] = new AttributeValue { S = $"ORDER#{orderId}" },
+ ["sk"] = new AttributeValue { S = "META" }
+ },
+ UpdateExpression = "SET #status = :status, #modified = :modified",
+ ExpressionAttributeNames = new Dictionary
+ {
+ ["#status"] = "orderStatus",
+ ["#modified"] = "modifiedAt"
+ },
+ ExpressionAttributeValues = new Dictionary
+ {
+ [":status"] = new AttributeValue { S = newStatus },
+ [":modified"] = new AttributeValue { S = modifiedAt.ToString("o") }
+ },
+ ReturnValues = ReturnValue.ALL_NEW
+ };
+
+ var response = await client.UpdateItemAsync(request);
+
+ if (response.Attributes == null || response.Attributes.Count == 0)
+ return null;
+
+ // Manual conversion of updated item to domain model
+ return new Order
+ {
+ Pk = response.Attributes["pk"].S,
+ Sk = response.Attributes["sk"].S,
+ OrderId = response.Attributes["orderId"].S,
+ CustomerId = response.Attributes["customerId"].S,
+ OrderDate = DateTime.Parse(response.Attributes["orderDate"].S),
+ Status = response.Attributes["orderStatus"].S,
+ TotalAmount = decimal.Parse(response.Attributes["totalAmount"].N)
+ };
+ }
+
+ ///
+ /// FluentDynamoDb manual builder - uses WithAttribute() and WithValue() methods.
+ ///
+ public static async Task FluentManualUpdateAsync(
+ OrdersTable table, string orderId, string newStatus, DateTime modifiedAt)
+ {
+ await table.Update()
+ .WithKey("pk", $"ORDER#{orderId}", "sk", "META")
+ .Set("SET #status = :status, #modified = :modified")
+ .WithAttribute("#status", "orderStatus")
+ .WithAttribute("#modified", "modifiedAt")
+ .WithValue(":status", newStatus)
+ .WithValue(":modified", modifiedAt.ToString("o"))
+ .UpdateAsync();
+ }
+
+ ///
+ /// FluentDynamoDb formatted string - demonstrates {0:o} ISO 8601 date formatting.
+ ///
+ public static async Task FluentFormattedUpdateAsync(
+ OrdersTable table, string orderId, string newStatus, DateTime modifiedAt)
+ {
+ await table.Update()
+ .WithKey("pk", Order.CreatePk(orderId), "sk", Order.CreateSk())
+ .Set("SET #status = {0}, #modified = {1:o}", newStatus, modifiedAt)
+ .WithAttribute("#status", "orderStatus")
+ .WithAttribute("#modified", "modifiedAt")
+ .UpdateAsync();
+ }
+
+ ///
+ /// FluentDynamoDb lambda expression - uses entity accessor with strongly-typed Set().
+ /// Note: Uses Status property which exists on Order entity (modifiedAt would need to be added to entity).
+ ///
+ public static async Task FluentLambdaUpdateAsync(
+ OrdersTable table, string orderId, string newStatus, DateTime modifiedAt)
+ {
+ await table.Orders.Update(Order.CreatePk(orderId), Order.CreateSk())
+ .Set(x => new OrderUpdateModel
+ {
+ Status = newStatus
+ })
+ .UpdateAsync();
+ }
+}