Continuing on from where we left off in the previous lesson, we’ll now look at how to programmatically add new customers into the Customer table of the ACME database. We’ll accomplish this by taking in data via the Presentation layer and then storing it in the Persistence layer. This will demonstrate the typical mechanics of using the Entity Framework to insert a new Entity into a database. While this lesson touches upon the “create” and “read” part of a typical “CRUD” set of operations, you can extend the principals learned here towards understanding the “update” and “delete” operations as well.
The first thing we’ll do is add Form Controls to the Default.aspx page in order to gather data that the customer input on the Presentation layer. Once again, we'll be using the source code to create the Server Controls for our page:
Back in CustomerRepository.cs of the Perisistence layer, we’ll first create a new method called AddCustomer() that returns void has an input parameter for a DTO.Customer. This method will create a new Customer (from Customer.cs), then fill it in with the values supplied from the DTO.Customer input argument:
Below the code we just wrote in the AddCustomer() method, we need to create a reference to the ACMEEntities database, adding the customer to it and then saving those changes with the SaveChanges() method:
Without the use of the Add() method, the changes would never be committed to the actual database set of customers, just kept locally in memory. Similarly, the SaveChanges() method is used whenever you make a change to the database; whether that be creating a Customer, updating or deleting one.
It should be obvious that we will only want specific types of data to be entered into the database. To ensure this, we can add validation before the changes are saved to the database through the invocation of the SavedChanges() method. For example, you can add some validation at the top of the AddCustomer() method to protect against an empty field being submitted for the customer’s name by throwing an Exception before the changes are saved:
You might then want to wrap the commit operation around a try/catch:
The example here is less than ideal. Normally, you would want to handle the Exception properly rather than re-throw it. Also, you would probably want to create a custom Exception that is handled in the Domain layer so as to avoid information bubbling up through layers that shouldn’t even be concerned with such details. The Domain layer, for example, shouldn't have any knowledge of an Entity Framework error, or even of the Entity Framework itself. The above approach will work in a pinch, however, just remember that you should strive to keep layers as separate as possible.
Next, we’ll create an AddCustomer() method in CustomerManager.cs of the Domain layer that simply calls the AddCustomer() method we had just created in the Persistence layer. This may seem redundant, however, keeping the implementation details of adding customers in the Domain layer helps maintain Separation of Concerns. Go to CustomerManager.cs and add the method:
You may be wondering if this step is necessary. After all, we're creating an entire method that simply calls a method in a different layer. The answer to this is yes and no. As we saw before, for a small application this is impractical. For a larger application with more requirements, however, this kind of functionality aids in maintainability throughout the lifecycle of the application.
Back in Default.aspx.cs we’ll add the following code to the okButton_Click event to create a new Customer and populate the properties with the information given by the user:
Immediately below that code, we’ll then call the AddCustomer() method from the Domain layer and pass in the Customer data. Note that it’s a good habit to wrap method calls to outside layers around a try/catch, especially when that method is performing some sort of data access. Here we’ll simply display the error message if an Exception is caught:
You should probably do the same to AddCustomer() in the CustomerManager.cs and actually perform some custom Exception Handling, including logging it:
Finally, take the code responsible for displaying customer data – which had already been in the Page_Load() method - and put it into a private method in Default.aspx.cs:
Call this method at the bottom of both Page_Load() and okButton_Click() to make sure the screen reflects the updated data when loading the page or clicking the OK button. When you run the application, enter customer data to see if everything is working correctly and successfully stores the data into the database:
Lesson 65 - Creating a New Instance of an Entity and Persisting it to the Database