Static Conversion Methods¶
Static conversion methods provide an inline, lightweight approach to custom type conversion in DynamoMapper. Static methods are defined directly on the mapper class, making them ideal for simple, mapper-specific conversions.
Overview¶
The current release supports named static methods on the mapper class for custom conversions.
When to Use Static Methods¶
Use static conversion methods when:
- Conversion logic is specific to a single mapper
- The conversion is simple and doesn't warrant a separate type
- You prefer co-location of mapping configuration and conversion logic
- No reuse across multiple mappers is needed
For reusable conversions across multiple mappers, create shared static helpers and call them from the mapper’s static conversion methods.
Required Method Signatures¶
Static conversion methods must follow exact signatures:
// Conversion TO DynamoDB AttributeValue
static AttributeValue ToMethodName(TProperty value);
// Conversion FROM DynamoDB AttributeValue
static TProperty FromMethodName(AttributeValue value);
Requirements: - Methods must be static - Methods must be declared on the mapper class - Return type and parameter type must match exactly as shown - Both To and From methods must be provided together
Basic Example¶
using Amazon.DynamoDBv2.Model;
public class OrderStatus
{
public string Name { get; }
public int Value { get; }
private OrderStatus(string name, int value)
{
Name = name;
Value = value;
}
public static readonly OrderStatus Pending = new("Pending", 0);
public static readonly OrderStatus Confirmed = new("Confirmed", 1);
public static readonly OrderStatus Shipped = new("Shipped", 2);
public static OrderStatus FromName(string name) => name switch
{
"Pending" => Pending,
"Confirmed" => Confirmed,
"Shipped" => Shipped,
_ => throw new ArgumentException($"Unknown status: {name}")
};
}
public class Order
{
public Guid OrderId { get; set; }
public OrderStatus Status { get; set; }
public decimal Total { get; set; }
}
[DynamoMapper(Convention = DynamoNamingConvention.CamelCase)]
[DynamoField(nameof(Order.Status), ToMethod = nameof(ToOrderStatus), FromMethod = nameof(FromOrderStatus))]
public static partial class OrderMapper
{
public static partial Dictionary<string, AttributeValue> ToItem(Order source);
public static partial Order FromItem(Dictionary<string, AttributeValue> item);
// Static conversion methods
static AttributeValue ToOrderStatus(OrderStatus status)
{
return new AttributeValue { S = status.Name };
}
static OrderStatus FromOrderStatus(AttributeValue value)
{
return OrderStatus.FromName(value.S);
}
}
Attribute Usage (Phase 1)¶
DynamoField Attribute¶
Configure static methods using the [DynamoField] attribute on the mapper class:
[DynamoMapper]
[DynamoField(nameof(Order.Status),
ToMethod = nameof(ToOrderStatus),
FromMethod = nameof(FromOrderStatus))]
public static partial class OrderMapper
{
public static partial Dictionary<string, AttributeValue> ToItem(Order source);
public static partial Order FromItem(Dictionary<string, AttributeValue> item);
}
Properties: - ToMethod - Name of the static method for To conversion (required) - FromMethod - Name of the static method for From conversion (required)
Constraints: - Both ToMethod and FromMethod must be specified together - Method names must reference existing, accessible static methods
DSL Usage (Phase 2)¶
In Phase 2, static methods will be configurable using the fluent DSL (planned):
[DynamoMapper]
public static partial class OrderMapper
{
public static partial Dictionary<string, AttributeValue> ToItem(Order source);
public static partial Order FromItem(Dictionary<string, AttributeValue> item);
static partial void Configure(DynamoMapBuilder<Order> map)
{
map.Property(x => x.Status)
.Using(nameof(ToOrderStatus), nameof(FromOrderStatus));
}
static AttributeValue ToOrderStatus(OrderStatus status)
{
return new AttributeValue { S = status.Name };
}
static OrderStatus FromOrderStatus(AttributeValue value)
{
return OrderStatus.FromName(value.S);
}
}
Multiple Static Conversions¶
You can define multiple static conversion method pairs in a single mapper:
[DynamoMapper(Convention = DynamoNamingConvention.CamelCase)]
[DynamoField(nameof(Product.Category), ToMethod = nameof(ToCategory), FromMethod = nameof(FromCategory))]
[DynamoField(nameof(Product.Status), ToMethod = nameof(ToProductStatus), FromMethod = nameof(FromProductStatus))]
public static partial class ProductMapper
{
public static partial Dictionary<string, AttributeValue> ToItem(Product source);
public static partial Product FromItem(Dictionary<string, AttributeValue> item);
// Category conversion
static AttributeValue ToCategory(ProductCategory category)
{
return new AttributeValue { S = category.Code };
}
static ProductCategory FromCategory(AttributeValue value)
{
return ProductCategory.FromCode(value.S);
}
// Status conversion
static AttributeValue ToProductStatus(ProductStatus status)
{
return new AttributeValue { S = status.Name };
}
static ProductStatus FromProductStatus(AttributeValue value)
{
return ProductStatus.FromName(value.S);
}
}
Nullable Types¶
The generator automatically handles nullable types. Your static methods should work with the non-nullable type:
public class User
{
public Guid UserId { get; set; }
public UserRole? Role { get; set; } // Nullable
}
[DynamoMapper(Convention = DynamoNamingConvention.CamelCase)]
[DynamoField(nameof(User.Role), ToMethod = nameof(ToUserRole), FromMethod = nameof(FromUserRole))]
public static partial class UserMapper
{
public static partial Dictionary<string, AttributeValue> ToItem(User source);
public static partial User FromItem(Dictionary<string, AttributeValue> item);
// Methods work with non-nullable UserRole
static AttributeValue ToUserRole(UserRole role)
{
return new AttributeValue { S = role.Name };
}
static UserRole FromUserRole(AttributeValue value)
{
return UserRole.FromName(value.S);
}
}
The generator wraps your methods with null checks as needed.
Advanced Example: Complex Value Objects¶
Static methods work well for complex value objects:
public class Money
{
public decimal Amount { get; }
public string Currency { get; }
public Money(decimal amount, string currency)
{
Amount = amount;
Currency = currency;
}
public override string ToString() => $"{Amount:F2} {Currency}";
public static Money Parse(string value)
{
var parts = value.Split(' ');
return new Money(decimal.Parse(parts[0]), parts[1]);
}
}
[DynamoMapper(Convention = DynamoNamingConvention.CamelCase)]
[DynamoField(nameof(Product.Price), ToMethod = nameof(ToMoney), FromMethod = nameof(FromMoney))]
public static partial class ProductMapper
{
public static partial Dictionary<string, AttributeValue> ToItem(Product source);
public static partial Product FromItem(Dictionary<string, AttributeValue> item);
static AttributeValue ToMoney(Money money)
{
// Store as string: "99.99 USD"
return new AttributeValue { S = money.ToString() };
}
static Money FromMoney(AttributeValue value)
{
return Money.Parse(value.S);
}
}
Diagnostics for Invalid Signatures¶
DynamoMapper validates static method signatures and emits compile-time diagnostics when a method is missing or has the wrong signature. Check the diagnostic message for the exact fix needed.
Best Practices¶
-
Use clear naming conventions
-
Keep methods simple
- Static methods should focus on conversion logic only
-
Complex business logic belongs elsewhere
-
Handle errors gracefully
-
Use static methods for mapper-specific conversions
-
If conversion logic is reused across mappers, use converter types instead
-
Document complex conversions
See Also¶
- Converter Types - Not supported in the current release
- Phase 1 Requirements - Detailed converter specifications
- Phase 2 DSL - DSL converter configuration