Why Not Entity Framework?
A common question we receive is: "Why didn't you build this as an Entity Framework Core provider?"
It's a fair question. EF Core has a provider model, and there are providers for various databases including some NoSQL options. However, after careful consideration, we concluded that an EF Core provider would actually work against developers trying to use DynamoDB effectively.
DynamoDB Is Not a Relational Database
Entity Framework was designed around relational database concepts: tables with rows and columns, foreign keys, joins, and flexible querying. DynamoDB operates on fundamentally different principles:
- No joins — Data must be denormalized or fetched in multiple requests
- No ad-hoc queries — Access patterns must be designed upfront
- Partition-based scaling — Data distribution affects performance dramatically
- Pay-per-request or provisioned capacity — Query efficiency directly impacts cost
Abstracting these differences away doesn't help developers — it hides critical information they need to build performant, cost-effective applications.
Enforcing Good Table Design
One of our core design principles is making it easy to do the right thing and hard to do the wrong thing.
Scans Must Be Explicitly Enabled
In DynamoDB, a Scan operation reads every item in a table. This is:
- Expensive (you pay for all read capacity consumed)
- Slow (especially on large tables)
- Often a sign of poor access pattern design
With FluentDynamoDB, tables must explicitly opt into allowing scans. This isn't a limitation — it's a guardrail that prompts developers to think about whether a scan is truly necessary or if a better access pattern exists.
// ❌ Without [Scannable], Scan operations are not available
[DynamoDbTable("Orders")]
public partial class Order
{
// Scan() method is NOT generated
}
// ✅ With [Scannable], Scan operations are explicitly enabled
[DynamoDbTable("Orders")]
[Scannable] // Explicitly opt-in to Scan operations
public partial class Order
{
[PartitionKey]
[DynamoDbAttribute("pk")]
public string Pk { get; set; } = string.Empty;
// ... other properties
}
// Now Scan is available
var allOrders = await table.Orders.Scan().ToListAsync();
Query vs Filter Expressions
DynamoDB has two types of expressions that filter data, and understanding the difference is crucial:
| Expression Type | When Evaluated | Cost Impact |
|---|---|---|
| Key Condition | Before reading data | Only matching items consume read capacity |
| Filter Expression | After reading data | All scanned items consume read capacity |
An EF Core provider would likely translate LINQ Where clauses into filter expressions, giving developers the illusion of flexible querying while silently consuming (and billing for) far more read capacity than necessary.
FluentDynamoDB makes this distinction explicit:
// TODO: Add code sample showing key condition vs filter expression
Indexes Are First-Class Citizens
DynamoDB's Global Secondary Indexes (GSIs) and Local Secondary Indexes (LSIs) are fundamental to good table design, not an afterthought.
Global Secondary Indexes (GSIs)
- Have their own partition and sort keys
- Can be added after table creation
- Have separate provisioned capacity
- Support eventual consistency only
Local Secondary Indexes (LSIs)
- Share the partition key with the base table
- Must be created with the table
- Share capacity with the base table
- Support strong consistency
An EF Core provider would struggle to surface these concepts naturally. In FluentDynamoDB, indexes are explicitly defined and queried:
// TODO: Add code sample showing index definition and querying
Single Table Design Is an Art
One of DynamoDB's most powerful patterns is single table design — storing multiple entity types in a single table with carefully crafted partition and sort keys. This enables:
- Fetching related entities in a single query
- Atomic transactions across entity types
- Simplified capacity management
But it requires intentional design:
PK SK Entity Type
─────────────────────────────────────────────────────────
USER#123 PROFILE User
USER#123 ORDER#2024-001 Order
USER#123 ORDER#2024-002 Order
PRODUCT#ABC METADATA Product
PRODUCT#ABC REVIEW#USER#456 Review
This isn't something that "just happens" with an ORM. It requires understanding your access patterns, designing your key schema, and making deliberate choices about data organization.
FluentDynamoDB embraces this complexity rather than hiding it, providing tools that make single table design manageable without pretending it's automatic.
The Right Abstraction Level
Entity Framework provides a high level of abstraction that works well for relational databases where:
- The query optimizer handles performance
- Indexes are suggestions, not requirements
- Ad-hoc queries are expected and efficient
DynamoDB requires a different abstraction level — one that:
- Makes access patterns explicit
- Surfaces the cost implications of operations
- Encourages upfront design rather than ad-hoc querying
FluentDynamoDB aims to reduce boilerplate and improve developer experience while keeping you aware of what's actually happening with your data.
When EF Core Might Be Right
If your application:
- Needs flexible, ad-hoc querying
- Has complex relationships requiring joins
- Doesn't have predictable access patterns
- Prioritizes development speed over operational cost
...then a relational database with EF Core might genuinely be a better fit than DynamoDB.
DynamoDB excels when you:
- Have well-defined access patterns
- Need consistent single-digit millisecond latency
- Require seamless scaling to any workload size
- Want predictable performance regardless of data size
FluentDynamoDB helps you succeed with DynamoDB by working with its design principles, not against them.