Better the devil you know - Part V.
Roger Torres - December 20th, 2008
In Part IV of this series I presented a type reader pattern that’s used by our DAL to read entity instances from the backing store.
While reading data is a big part of any enterprise application, it’s just about half of the story. To complete the CRUD circle, developers Create, Update, and Delete objects, persisting the changes back to the data store.
COMMAND BINDERS
We already discussed how to insert records invoking simple commands, but we didn’t see any domain model in the action. Our example was completely based on the command class and its properties feeding SQL parameter values. What many developers would expect is an interface to “dematerialize” and persist entity instances directly from the domain model to the backing store, abstracting away the extra mapping layer. This is exactly what the command binder interface does for us.
The following code revisits the example to insert employees, but this time using command binders:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | public class InsertEmployee : Command, IBinder<Employee> { [CoNatural.Data.Parameter(System.Data.ParameterDirection.Output)] public int Id { get; set; } [CoNatural.Data.Parameter(50)] public string FirstName { get; set; } [CoNatural.Data.Parameter(50)] public string LastName { get; set; } public DateTime HireDate { get; set; } #region IBinder<Employee> Members public void SetInputValues(Employee instance) { FirstName = instance.FirstName; LastName = instance.LastName; HireDate = instance.HireDate; } public void GetOutputValues(Employee instance) { instance.EmployeeId = Id; } #endregion } |
1 2 3 4 5 6 7 8 | Employee e = new Employee() { FirstName = "Johnny", LastName = "Does", HireDate = new DateTime(2007, 1, 1) }; cn.ExecuteBinder<Employee>(new InsertEmployee(), e); int newId = e.EmployeeId; |
The command binder interface only requires two operations:
- Set the command’s property values from the entity instance before the command is executed. These values will feed the SQL input parameters.
- Get the command’s property values (the ones updated after the execution) to populate the entity instance with the results. These map to SQL output parameters.
The example is trivial since the mappings are very linear, but in real applications we will find more complex scenarios where different business rules and validations are part of the binding logic, or when a single command must be bound to different types of entities (for example to persist a .NET class hierarchy). The main goal here is to provide a very simple layer to compensate for a well known problem - the object-relational impedance mismatch.
We will see more examples and the application of command binders in the next post when we discuss the last component of this framework: Batch Execution.
Stay tuned.