Whenever there's a mismatch between your RDBMS Data Model classes and the preferred response you want your service to provide, you should define separate POCOs (i.e. DTOs) that define the data you want your services to return i.e. the Response DTO.
This is fairly common in batchful responses where your RDBMS's relational POCOs do not match the shape of your Response DTOs which tend to be more heirachal. You'd also want to do this if you only want to provide a subset (i.e. hide) of the data that's stored in your DB tables.
//DataModel classes (i.e. DB Tables)
public class Customer {
[AutoIncrement]
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
[Index(Unique = true)] // Creates Unique Index
public string Email { get; set; }
}
public class Order {
[AutoIncrement]
public int Id { get; set; }
[References(typeof(Customer))] //Creates Foreign Key
public int CustomerId { get; set; }
public DateTime? OrderDate { get; set; }
public decimal Freight { get; set; }
public decimal Total { get; set; }
}
...
//DTOs - what your web service returns.
public class CustomerOrders
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public List<OrderSummary> Orders { get; set; }
}
public class OrderSummary
{
public int OrderId { get; set; }
public DateTime? OrderDate { get; set; }
public decimal Freight { get; set; }
public decimal Total { get; set; }
}
....
//I personally like to store Mapping logic separately in Ext methods
public static class TranslationExtensions
{
public static CustomerOrders ToCustomerOrders(this Customer from, List<Order> orders)
{
var to = customer.TranslateTo<CustomerOrders>();
to.Orders = orders.ConvertTo(x => x.ToOrderSummary());
}
public static OrderSummary ToOrderSummary(this Order from)
{
var to = from.TranslateTo<OrderSummary>();
to.OrderId = from.Id; //manually populate non-matching properties
return to;
}
}
...
public override object OnGet(CustomerOrders request)
{
var customer = dbCmd.QueryById<Customer>(1);
var custOrders = dbCmd.Where<Order>("CustomerId = @Id", new { customer.Id });
var dto = customer.ToCustomerOrders(custOrders); // <-- Mapping from DB to DTOs here
return dto;
}
public override object OnGet(UserProfile request)
{
var session = this.GetSession();
var userProfile = session.TranslateTo<UserProfile>();
userProfile.Id = int.Parse(session.UserAuthId);
var user = DbFactory.Exec(dbCmd => dbCmd.QueryById<User>(userProfile.Id));
userProfile.PopulateWith(user);
return new UserProfileResponse {
Result = userProfile
};
}