Putting Studio for Entity Framework to use

A Brief Guide

Dom Sinclair

Table of Contents Foreword ...... 4 Introduction ...... 5 Getting Started: The Data Model ...... 7 Getting Started: Referencing the data model ...... 10 Getting Started: The C1DataSource Component ...... 11 Getting Started: Binding controls to the C1DataSource ...... 17 Querying, Editing and Adding data with the C1DataSource ...... 25 Querying Data without writing code ...... 25 Saving Changes made to the data ...... 28 Using the S.E.F. for a real world example ...... 31 Database first or Code first? ...... 32 The Data Model ...... 32 The Entity Model Connection String ...... 36 Entity Framework Connection Strings ...... 36 Creating a dynamic connection string for the SEF ...... 37 Extending the Data Model ...... 41 Building the first User Interface ...... 45 Validating, Saving and the whole business of Transactions ...... 53 Basic Validation ...... 53 Saving the data ...... 56

Figure 1: The Add New Item Dialog ...... 7 Figure 2: Add Data Model Wizard; Stage 1 ...... 8 Figure 3: Add Data Model Wizard; Stage 2 ...... 8 Figure 4: Add Data Model Wizard; Stage 3 ...... 9 Figure 5: The completed Entity Data Model ...... 9 Figure 6: Solution Explorer showing the solution after the data model project has been added ...... 10 Figure 7: Solution Explorer showing the reference to the data model added to the SefTrial project ...... 11 Figure 8: C1 Studio for Entity Framework as it appears in the Visual Studio Toolbox ...... 11 Figure 9: Setting the Specific Version Property ...... 12 Figure 10: The properties window for the C1DataSource ...... 13 Figure 11: The EntityViewSouce Collections Editor of the C1DataSource ...... 13 2

Figure 12: Changing the DataMember and DataSource properties of the C1FlexGrid ...... 14 Figure 13: The drop down you'll see in the DataMember property of the grid showing The Products table accessible from Categories...... 14 Figure 14: The SefTrial showing the Category and Products tables...... 15 Figure 15: The Entity Framework attempting to resolve the relationship between Categories and Products...... 16 Figure 16: The special ControlHandler property added by the C1DataSource ...... 16 Figure 17: Resolving the relationship between Categories and Products with the C1DataSource...... 17 Figure 18: The DataBindings section in a standard Text Box's Properties dialog...... 18 Figure 19: The Formatting and Advanced Binding Dialog...... 19 Figure 20: Setting the Data Source Update Mode...... 20 Figure 21: Setting the Text property of a standard TextBox to a Data Source in the properties window...... 21 Figure 22: The properties window for a C1 TextBox showing their additional properties that make Data Binding a little easier...... 21 Figure 23: The SefTrial showing the addition of text boxes to display Category data...... 22 Figure 24: The Edit Items Dialog of the C1 InputPanel ...... 23 Figure 25: The project settings showing the application tab ...... 23 Figure 26: The C1 Input Panel displaying the Categories table...... 24 Figure 27: The FilterDescriptor Properties Collection Editor ...... 26 Figure 28: The available options for the Operator property of the Filter Descriptor ...... 26 Figure 29: The SortDescriptor Properties Collection Editor ...... 27 Figure 30: The database diagram of the database section to be modelled ...... 33 Figure 31: The Entity Data Model as created by Visual Studio...... 34 Figure 32: The Data Connection Dialog configured to only allow SqlClient connections...... 39 Figure 33: The relationship between Sites and Extinguisher Locations...... 41 Figure 34: A typical problem that might occur where the same information appears in the field that the SEF uses to resolve relations between tables...... 42 Figure 35: The FlexGid configured to enter Extinguisher locations...... 46 Figure 36: Fields in the Extinguisher Locations Table...... 47

3

Foreword

In September of 2010 I decided to treat myself to a little light reading for my annual break. The book in question was on the Entity Framework, a subject I’d read a few articles on and one which I felt I ought to learn a little more about. The book was a revelation, convincing me that in the future any new data centric applications that I was going to build or seriously upgrade should make use of it.

A couple of months later I suggested to friend that he read the book I was in the process of re-reading for the third time. I’m glad to say that he was as enthused about it as I was. A few months went by and late one Friday evening he sent me an email containing what was in reality the first version of what was later to become known as the Studio for Entity Framework.

Since then I’ve spent hours playing with it and been very privileged to converse with some extremely clever developers in the process. Throughout that time they have patiently and diligently answered some quite inane questions on my part whilst I developed a better understanding of just what could be achieved with the Studio for Entity Framework.

To that end I’d like to thank the following individuals for their generosity and assistance over the months;

Bernardo Castilho

Michael Eisenstein

Nodir Turakulov

Without them this wouldn’t have been possible.

4

Introduction

With Studio for Entity Framework having been officially released now for a few months it is perhaps the time to have a detailed look at just exactly what it does and how it can be incorporated into your applications. This isn’t the place to go into a detailed history of the Entity Framework, suffice to say that its underlying principle is to allow developers (and I guess if you’re reading this then that includes you!) to work against a model of their data rather than the actual database itself. It’s built very firmly upon the ado.net platform, so much of what you already know if you’re used to working with that will still be relevant, but it takes it further.

If you’re new to the entity framework then you should obtain a copy of what has rapidly become considered as the ‘bible’ for this, Julie Lerman’s excellent ‘Programming Entity Framework’. Two versions of this are available. The first (published in February 2009) deals with the Entity Framework version 1.0. The second published just over a year later is a substantially revised version that takes into account the changes that were made to Entity Framework version 4.0 (there were incidentally no Entity Framework versions 2.0 and 3.0). Arguably you could dispense with the first edition and just get the second, however if you’re new to this, and if you happen to prefer using VB as opposed to C# then a copy of both wouldn’t go amiss. Julie has since written two new books to add to the collection dealing with the enhancements made to the Entity Framework in version 4.1. Code First, not unsurprisingly, deals with the code first approach to the Entity Framework whilst DBContext delves into greater depth on the matter of the DB Context Api.

There is one last point to consider before we delve into the Studio. As the Entity Framework has matured and it becomes more clear the emphasis that Microsoft themselves have placed on it (you need look no further than LightSwitch for proof of that) a question often asked in various forums running along the lines of ‘Should I be changing the way my application handles data?’ deserves to be answered. Well the pragmatic answer to this would have to be, if it ain’t broke… ; however if you’re about to embark on a new project or a major revision of an existing application then you owe it to yourself to give the Entity Framework serious consideration. If that consideration leaves you thinking that adopting it makes sense then this book will hopefully help to convince you that doing so with the Studio for Entity Framework makes even more sense.

NB:

Studio for Entity Framework requires the .Net Framework 4.0. If you’d looked at early betas of it you’ll be aware that at that time it also required that any application in which it was used targeted the full .Net 4.0 framework. With its official release the Studio can be used with the client profile, however it’s utilisation of the .Net 4.0 framework does mean that you will need to be using Visual Studio 2010 for any development work. At the time of writing this or perhaps to be a little more accurate as the writing of this was taking place the Entity Framework v5.0 began to appear in beta and CTP. This adds several new features to Entity Framework, but also raises the requirement from .net Framework 4.0 to 4.5. The likelihood is that using Entity Framework 5.0 will require that you develop in the new Visual Studio 2012 and that any applications you develop with it will only work on Windows Vista or above.

Screen shots used throughout these articles that demonstrate the use of code will show the Studio for Entity Framework being used with VB.Net. This is simply because the author happens to be more at home with VB than with C#, however code samples will (where appropriate) be provided in both VB and C#. To begin with at least we’ll employ the ubiquitous Northwind Database as our example but as we progress we’ll employ a custom database to help illustrate the theories and concepts involved. To begin with, Winforms will be the primary platform used and we’ll also make use of a variety of C1 controls that are available for that platform. As we progress then we’ll look at other platforms as well as Linq and the great work that C1 did in extending Linq with LiveLinq.

5

This introduction will, quite deliberately, be a relatively simple guide to taking your first steps towards using the Studio for Entity Framework. There will be a number of illustrations showing different aspects of the getting started process. For some of you this may well be familiar territory. Future chapters will assume that you’re familiar with the fundamentals but for now at least it’s important to get novices onto the right track.

6

Getting Started: The Data Model

Prior to any work with the Studio for Entity Framework you’re going to need a data model against which you can work. Entity Framework supports both code first modelling (where you begin by actively designing and creating the classes that will form the basis of your database at a later stage) and database first modelling (where you make use of an existing database). To begin with we’ll look at a database first model and we’ll also follow what many developers’ describe as being best practice and create our model (and only our model) in the first project we work on. This will result in us having a single model that we can reuse in multiple projects with the added benefit that changes to the model itself only ever need to be made in one place.

Begin by opening Visual Studio and creating a new project (select class for this) and choose a short name for your project, we’ll use ‘NW ‘(the benefits of a short name will become all too apparent later on!) By default a new Class (‘Class1’) will be created. This can be safely deleted. Now select ‘Add New Item’ from the project menu, and in the dialog that opens select ADO.NET Entity Data Model. Give the model a meaningful name (we’ll use NWind.edmx) and click ‘Add’.

Figure 1: The Add New Item Dialog

In the ensuing dialog select ‘Generate from database’ and click next.

7

Figure 2: Add Data Model Wizard; Stage 1

The next dialog will prompt us to create a connection to the database. You may well have a preconfigured connection to Northwind, in which case use it, if not then click ‘New Connection’ and follow the ensuing dialogs to create a connection to your copy of Northwind. Once completed you will return to this dialog, but before clicking next change the default name for the entity set that is about to be created from’ NorthwindEntities’ to ‘NwEntities’.

Figure 3: Add Data Model Wizard; Stage 2 8

In the next dialog expand the ‘tables’ node and check the ‘Categories’ and ‘Products’ tables. For consistency change the name for the model Namespace that is about to be created to ’NwModel’ and then click ‘Finish’.

Figure 4: Add Data Model Wizard; Stage 3

Visual Studio will now create your model and when finished it will open up in the model designer and should look not dissimilar to this;

Figure 5: The completed Entity Data Model

Build and save your project. You’ve now created the Entity Data Model that we’ll use from now on.

9

Getting Started: Referencing the data model

Having built our data model we’ll need to reference in it any projects that we create in future. This is a very simple task.

Begin by creating a new project in Visual Studio, this time we’ll create a standard Windows Form project. Choose a suitable name (in this example we’ll use ‘SefTrial’) and create your project. As soon as Visual Studio has created it right click on the solution name in ‘Solution Explorer’ and in the context menu that appears select Add: Existing Project. Navigate to the NW project that we created for our data model and select it. When done you should see the following in ‘Solution Explorer’.

Figure 6: Solution Explorer showing the solution after the data model project has been added

Before we proceed there are two things that we need to do.

1. We need a reference to the connection string that was added to the App.Config file in our data model project. As our new SefTrial project doesn’t as yet have anything in its App.Config file then the easiest way to get it is to simply copy the file from the NW project and paste it into the SefTrial (saying yes when prompted if you wish to overwrite the existing ‘App.Config’ file. 2. We need to add a reference to the NW project in the SefTrial.

When you’ve completed both these tasks you should see the following in ‘Solution Explorer’.

10

Figure 7: Solution Explorer showing the reference to the data model added to the SefTrial project

For good measure now would be a good time to build and save your new project.

Getting Started: The C1DataSource Component

When you installed the Studio for Entity Framework a new tab will have been added to the Toolbox in Visual Studio and within that you’ll find a single control, the C1DataSource.

Figure 8: C1 Studio for Entity Framework as it appears in the Visual Studio Toolbox

C1DataSource is a non-visual control which means that when you add it to your forms it will appear in the toolbar beneath them. Go ahead and add one to your form.

11

At the same time as the C1DataSource was added to your form some more assemblies were added to the project, amongst which were the C1.data.Entity.dll, the C1.Win.Data.Entities.dll and the C1.LiveLinq.dll. There is a small change to the properties of these referenced assemblies which, whilst not essential, I would suggest that it makes good sense to apply at this stage. Under the References section of the SefTrial Project in the Solution Explorer click on C1.Data.Entity and in the properties for the C1.Data.Entity.dll set its Specific Version Property to False.

Figure 9: Setting the Specific Version Property

Carry on and do the same for the C1.LiveLinq.dll and the C1.Win.Data.Entities.dll. Later on as you make reference to other C1 controls (or indeed any other third party controls) do exactly the same. The reason behind suggestion that you do this is because as you work on the initial development of an application and almost certainly as you continue to maintain that application over its lifecycle the third party controls that you have employed may well be upgraded. Having the Specific Version set to False ensures that you can upgrade these controls without fear of them causing errors within your project in the design environment of Visual Studio itself later on.1

Now in the properties dialog for the C1DataSource1 that has just been added make the following changes; Change the name to cds (actually there is no real need to change the default name but I personally prefer to work with names that mean something to me). From the dropdown next to ObjectContextType select NW.NwEntities.

1 If you happen to use CodeRush then it has a rather useful feature to assist with this, namely Default Reference Properties for Projects. 12

Figure 10: The properties window for the C1DataSource

Now open up the ViewSourceCollection from the properties window and in the dialog that opens click ‘Add’.

Figure 11: The EntityViewSouce Collections Editor of the C1DataSource

In the dropdown next to EntitySetName select ‘Categories’. Click ‘OK’.

Now let’s return to our form, enlarge it a little and add a C1FlexGrid to it. Once the grid is there, make the following changes to its properties;

Name flex1 DataSource cds (that’s the c1datasource that we added to the form) DataMember Categories ExtendLastCol True (as ‘Categories’ only has three columns this will ensure we fill the grid)

13

Figure 12: Changing the DataMember and DataSource properties of the C1FlexGrid

Build and Run the application. You’ll see a form with a grid containing all of the rows from the ‘Categories’ table. Click in the caption of each column and you’ll see the data sort itself automatically. All of this has been achieved without you having to write a single line of code.

Next we’ll add a navigation control to the form. From the toolbox drag a C1DBNavigator onto the form, set its DataSource property to the c1DataSource (cds), its DataMember property to ‘Categories’ and just to make it look a little better set its ColorButtons Property to true. Run the application and you’ll see that you can use the navigator to move through the records on the grid, moreover you’ve still not written a single line of code.

There is one last task for this section. Enlarge your form a bit and add a second C1FlexGrid below the first. Set the following properties of the new grid;

Name flex2 DataSource cds DataMember Products (you’ll find Products by clicking on the arrow next to categories)

Figure 13: The drop down you'll see in the DataMember property of the grid showing The Products table accessible from Categories

14

Run the application and notice how as you move between the category record using the navigator all the products associated with that category now appear in the second grid that we’ve just added to our form. Take some time to play with the two grids. Notice how you can sort the data by clicking in the captions of the various columns, you can even edit data in the various rows.

Figure 14: The SefTrial showing the Category and Products tables

If you scroll to the far right of the second grid you’ll see a column called Category. This column represents the relation that exists between the ‘Categories’ and the ‘Products’ tables.2 The Entity Model knows this relationship exists and has added it to the second grid, but no equivalent column actually exists in the Products’ Table so when we come to run the application there’s no data to actually populate this column. The Entity Framework does the only thing it can do under the circumstances and fills each row with the name of the relationship (in this case NW.Category).

2 If you look at Figure 5: The completed Entity Data Model you can see the Category relationship defined at the bottom of the products table. 15

Figure 15: The Entity Framework attempting to resolve the relationship between Categories and Products.

We could just open up the designer of the C1FlexGrid and remove this column to avoid having to look at this meaningless data. However the C1DataSource has a trick up its sleeve to help us get around this. Open up the properties of the second grid and find its ControlHandler On cds Property. Expand it and set AutoLookup to True.

Figure 16: The special ControlHandler property added by the C1DataSource

Run the application again and this time you’ll see that the column has some meaningful data in it. Not bad, and you still haven’t had to write a single line of code.

16

Figure 17: Resolving the relationship between Categories and Products with the C1DataSource.

Getting Started: Binding controls to the C1DataSource

Finally in this section we’re going to take a look at how we can bind the C1DataSource to various Winforms controls. To begin with we’ll examine the no code route and once we’ve done that look at some of the ways that we can query the data that we want shown in our application so that it’s a little more relevant to the end user. Whilst the emphasis is likely to focus on controls that can be found in the ComponentOne Studio for Winforms suite bear in mind that in reality what you’re about to learn applies to just about every data aware control in the standard collection of controls that ship with Visual Studio.

The use of the term ‘data aware’ was very deliberate. Some controls (text boxes and grids for example) lend themselves very obviously to the display and manipulation of data, others ( group boxes or plain tab controls) would, in and of themselves, prove to be rather difficult to associate with raw data. Those controls that are data aware generally have the following two properties;

DataMember DataSource 17

The DataSource property will usually be set to C1DataSource1 (if you have left it with its default name).

The DataMember property will usually be set to the entity name defined in the ViewSource collection(s) of the C1DataSource1 where the control on which it is being set is one capable of displaying more than one field. In this instance a data grid would be a good example of just such a control. Thinking back to the simple application that we built in the last section then this would relate to the two C1FlexGrids’ DataMember properties being set to Categories and Products respectively.

Text boxes on the other hand are more suited to displaying a single field.

With a standard textbox that can be found in the section of the toolbox in visual studio we need to bind it to a data source via its advanced bindings;

Figure 18: The DataBindings section in a standard Text Box's Properties dialog.

And from there open up the Formatting and Advanced Binding Dialog where we can select the field that we want it to be bound to;

18

Figure 19: The Formatting and Advanced Binding Dialog.

And then finally we can chose how we wish to have the data source updated. When working with the SEF the default OnValidation will probably suffice.

19

Figure 20: Setting the Data Source Update Mode.

As an alternative to using the Formatting and Advanced Binding Dialog you could just set the text property from the DataBindings in the properties window;

20

Figure 21: Setting the Text property of a standard TextBox to a Data Source in the properties window.

ComponentOne chose to add specific DataField and DataSource properties to their own textbox control which are easily accessible from the standard properties window;

Figure 22: The properties window for a C1 TextBox showing their additional properties that make Data Binding a little easier.

21 and as such in their case the DataSource property would be set first and then the DataField property would be set to the specific field that you wished to display. So for example if we wished to have a form displaying individual records for the Categories table we would need to have three separate text box controls with their DataBindings set respectively to CategoryID, CategoryName and Description. Of course on such a form you would also require a navigation control to navigate through the records.

Returning to the simple application that we built earlier, add a couple of ComponentOne Text boxes to the form. Set their DataSource properties to the C1DataSource on the form and their DataField properties to CategoryName and Description respectively. Build and run the application and as you will see as you scroll through the records the text boxes will display the name and description for the category that is currently selected.

Figure 23: The SefTrial showing the addition of text boxes to display Category data

So as you can see it’s actually relatively easy to bind controls to the C1DataSource and get them to display data. In all probability the most difficult task that you’re going to face is getting the controls on your form to line up nicely. As luck would have it ComponentOne make that task even easier for you if you are working in Winforms. Within the Visual Studio Toolbox under the C1 Winforms tab you’ll find the C1 InputPanel control.

Add a new form to application that we’ve been working on (make sure that you add it to the SefTrial project) and once it’s open add a C1DataSource to it setting up its properties in exactly the same manner as you did before. Now drag a C1 InputPanel onto the form, set its Dock Property to fill, its DataSource property to the C1DataSource and its DataMember property to Categories. You’ll now see the InputPanel create a complete form for you. From the smart

22 tag of the input panel select ‘Edit Items’ and change the text of the hdrC1DataSource from ‘&C1DataSource’ to ‘&Categories’3.

Figure 24: The Edit Items Dialog of the C1 InputPanel

Open up the project settings, and on the application tab set the start-up form to be the one that you’ve just created.

Figure 25: The project settings showing the application tab

Build and run the application. The Input Panel has produced a fully configured and nicely laid out form which displays all of the rows in the category table as you scroll through them. You’ll also see that where they exist in a table the Input Panel is also capable of displaying pictures.

3 The use of the ampersand (&) here means that the Character immediately after it will become a hot key. 23

Figure 26: The C1 Input Panel displaying the Categories table.

Once again we have been able to produce a form that provides a comprehensive display of data from a table in the Northwind database and we’ve been able to do so without actually writing a single line of code. Incidentally it is worth mentioning that the quality of the image displayed in the C1InputPanel is not a limitation of the panel, rather it is to do with the poor quality of the original image itself.

That effectively concludes the introduction. I’ll apologise now if you’ve found aspects of this a little simplistic but for now it’s been important to ensure that our basic data model was created properly and equally that simple property setting for the C1DataSource and associated controls used to display data was thoroughly explained. From now on we’ll work on the assumption that you’re happy doing this on your own and we’ll concentrate on what you really can achieve with the Studio for Entity Framework.

24

Querying, Editing and Adding data with the C1DataSource

You have now been introduced to the C1DataSource control that is part of the Studio for Entity Framework. Everything that we’ve done with it has been done without the need to write a single line of code. Now we are going to look at how the C1DataSource can be made to handle data in a way that is of much more use to us. We’ll see how data can be filtered and sorted, initially without the need to write any code and then we’ll go on to see how, by writing just a little code, we can add editing and the addition and deletion of records to our skillset.

By the end of this section you should be fairly comfortable using the C1DataSource and be able to produce some really quite impressive results in your applications. Before we begin however let’s add some more tables from the Northwind database to our data model. Open up the SefTrial application that we’ve been working on and in the solution explorer select and open the NWind.edmx data model.

Once the model opens up on the design surface right click with your mouse and select ‘Update Model from the Database’ from the context menu that appears. In the dialog that then appears check the box next to Tables to add the remaining tables from the Northwind database. Click finish and then you’ll see them added to the model. Now rebuild the application (specifically you must ensure that the NW project is rebuilt so that the changes that you have made to the data model will be picked up in the SefTrial project).

It’s important to realise at this stage that although the changes that we have made to the NW project have occurred whilst it has been associated with the SefTrial project they are not dependent on the SefTrial project. In other words you could now built a fresh application, include the NW project in it and have access to the full Northwind data model. This is one of the key benefits of the Entity Framework, its ability to provide you with the means to make a model of your data which can be used in any number of applications and against a wide variety of different platforms.

One of the things we will need to be able to do in this section on working with data is to flip between forms whilst the application is still open. For that we are going to need to add a main form with the ability to navigate between the various forms that we are about to add. How you construct such a form is of your choosing, but now would be a good time to build such a form and ensure that it is set to be the main form that opens in your application.

Querying Data without writing code

With the additions to the data model that you have made you should now have access to the Customers table. This has many more rows than the Category table ( some 91 as opposed to just 8) and whilst it is by no means an immense collection it may well be of more use to our end user if we can present them with the data it contains in a more concise fashion rather than just serving everything up at once.

If you examine the Customers table in something like SQL Server Management Studio you’ll see that some of the Customers in the table are based in London. Let’s begin by just getting these customers. Create a new form and add a C1DataSource to it. Associate the C1DataSource with the NWindEntities and open its ViewSource collection editor. Set the EntitySetName Property to Customers. Now, before you click OK open the Filter Descriptors collection editor and click ‘Add’.

As soon as the FilterDescriptorProperties Collection Editor opens click ‘Add’. A new Filter Descriptor is created.

25

Figure 27: The FilterDescriptor Properties Collection Editor

Let’s just take a couple of moments to look at the properties that we can set for this descriptor.

 Ignored Value: This property name might at first suggest that this is a specific value that we wish to ignore in the returned set of filtered records, which isn’t actually the case. The purpose of this property is to allow the user (usually in code) to disable the entire condition (the FilterDescriptor) without actually deleting it. To clarify this, let’s suppose that you were to have a form on which you had placed a combo box whose selected index you intend to use as the FilterDescriptor value. If no selection is made in the combo box then its selected index will be -1. By setting the ignored value to -1 we would be automatically disabling the FilterDescriptor condition if nothing is selected in the combo box. The default value is blank or null.  IsCaseSensitive: By default filters (especially those where you might be searching for all instances of a field beginning with a certain letter) will be case insensitive. So if you specifically require the filter to return an upper or lowercase result then set this to true.  Operator: The operator is in essence the type of filter that will be applied. You should make your selection from the drop down provided.

Figure 28: The available options for the Operator property of the Filter Descriptor

26

 PropertyPath: This is the record field on which you wish to filter the records.  Value: This is the actual value of the filter that will be applied.

So in this case we will be filtering the Customers to return only those records where the field ‘City’ value is equal to London (or london (remembering that the filter is case insensitive)). Set the properties as you see in the illustration above and then click ‘OK’, and then ‘OK’ once again.

Associate this form with the main navigation form that you added and then run the application. Open the new form and you should see six records returned by the filter.

By default these records will have been sorted by CustomerID: Ascending (in actual fact if no sort order is defined then the records are sorted by the Primary Key in ascending order). We can however change the sort order if we wish.

Once again open up the ViewSource collection editor of the C1DataSouce on the form we have been working on and this time scroll down the list of properties until you find SortDescriptors and open up its collections editor and click ‘Add’.

Figure 29: The SortDescriptor Properties Collection Editor

Leave the Direction property in its default of Ascending and type ContactName into the PropertyPath property. Click ‘OK’ and then ‘OK’. Build and run the application. Open up the form and once again we have the six records returned by the filter we set but this time sorted by ContactName. We have yet to write a line of code!

A ViewSource can have multiple filters and multiple SortDescriptors making it possible to define what would be, if written in conventional , quite complex queries. 27

**************

Before we leave the realms of working with data in The Studio for Entity Framework without writing any code at all it’s time to introduce one very important concept about the Studio that you need to both understand and begin to appreciate its profound significance.

Quickly create another form containing a C1InputPanel and a C1DataSouce. Set them up as before to show the customers table, but don’t bother applying any filters. Once completed ensure that you add the ability to navigate to it from the main form. Build and run the application and open up the filtered customers form. Scroll through the records until you reach the record for the company ‘Around the Horn’ (it should be the fifth record). Now edit some of the fields EXCEPT the CompanyID. Close the form BUT DO NOT CLOSE THE APPLICATION; instead open up the new form you just created showing all of the Customer records. The first record to be displayed will be that for the company ‘Around the Horn’.

Notice that the edits that you made to this record in the last form you had open and then closed (without saving anything) have been persisted and appear here in this form.

What you have just witnessed is the EntityClientCache in action. Studio for Entity Framework creates an EntityClientCache of the data derived from the entity data model. The scope of this is not simply limited to the individual forms where it is utilised by the C1DataSource, it is in fact application wide. Changes that you make to data on one form (even if you simply close the form and move on) will be retained in the EntityClientCache all the while that the application is open and nothing has been done to either close or refresh it (the EntityClientCache).

Take a couple of minutes to reflect on that last statement, the concept of an application wide scope of data, the ability to edit data in one place and see those changes reflected elsewhere without needing to invoke a save changes action. Arguably the EntityClientCache is the most important addition that the Studio for Entity Framework confers to the plain Entity Framework, but the benefits that it brings also bring with them a new responsibility on your part as a developer to safeguard the integrity of your end user’s data. No longer can you assume that simply closing a form will eradicate any changes made to the underlying data that might have taken place prior to its closure.

Fortunately the developers behind the Studio for Entity Framework were already one step ahead and the Studio adds the benefit of Client Transactions to the Entity Framework. The whole concept of Transactions is too complex to go into here, it deserves a chapter to itself and accordingly we will return to it later on.

Saving Changes made to the data

Up to this point everything that we have done has been accomplished without the need to write a single line of code. That’s about to change as we look at how to persist any changes that we make to the data that underlies our applications.

Return to the form we built to display filtered customers and select the navigator control at the top of the input panel. Change its ‘ShowSaveButton’ Property to true and then in the navigator’s ButtonClick event add the following code:

28

Private Sub navC1DataSource_ButtonClick(sender As Object, e As C1.Win.C1InputPanel.InputNavigat orClickEventArgs) Handles navC1DataSource.ButtonClick If e.Button = C1.Win.C1InputPanel.InputNavigatorButton.Save Then C1DataSource1.SaveChanges() End If End Sub

private void navC1DataSource_ButtonClick(object sender, C1.Win.C1InputPanel.InputNavigatorClickEventArgs e) { if (e.Button == C1.Win.C1InputPanel.InputNavigatorButton.Save) { C1DataSource1.SaveChanges(); } }

That single line, C1DataSource1.SaveChanges(), is sufficient to perpetuate the changes that you make back to the underlying database.

Run the application, open the filtered customers form and navigate to the fifth record (‘Around the Horn’). Edit the ‘Contact Title’ field so that it reads Sales Manager and once done click save. Close the application, run it once again and this time open up the unfiltered customers form. The change you made has been saved to the database.

NB

Closing the application was necessary so that we did not get fooled into thinking that our change had been successful when in reality we were just witnessing the effect of the application wide scope of the ClientCache.

Now run the application again and once more open the filtered customers form and navigate to the fifth record. This time copy the Customer Id for ‘Around the Horn’ and when you’ve done that click the Add Record button on the navigator at the top of the screen. A new record will be created. In the Customer Id field paste the id that you have just copied and then add a name to the company name field. Once that’s done click the save button. At this point the application will fail with an unhandled exception.

Arguably what has just happened was a little too contrived but it does serve to illustrate a rather important point quite well. Whilst calling SaveChanges() will suffice to save any changes that you make to the data it has no built in way to elegantly back down in the event that something goes awry as that data is being saved. In this particular case we created a duplicate primary key deliberately breaking a constraint on the table that all such keys be unique. As the developer you should be aware that this sort of thing can happen and it is therefore your responsibility to allow for the possibility. In this instance a Try Catch block should do the trick.

29

Private Sub navC1DataSource_ButtonClick(sender As Object, e As C1.Win.C1InputPanel .InputNavigatorClickEventArgs) Handles navC1DataSource.ButtonClick If e.Button = C1.Win.C1InputPanel.InputNavigatorButton.Save Then Try C1DataSource1.SaveChanges() Catch ex as exception MessageBox.Show(ex.Message.ToString) End Try End If End Sub

private void navC1DataSource_ButtonClick(object sender, C1.Win.C1InputPanel.InputNavigatorClickEventArgs e) { if (e.Button == C1.Win.C1InputPanel.InputNavigatorButton.Save) { try { C1DataSource1.SaveChanges(); } catch (exception ex) { MessageBox.Show(ex.Message.ToString()); } } }

Admittedly a very simple implementation of some basic error handling, in a real world application you would want to do a little more than simply relaying the exception message to a message box, but at least it will avoid the unhandled exception that was produced without it.

30

Using the S.E.F. for a real world example

Up to now we have really just looked at what it is possible to achieve with the Studio for Entity Framework by showing a few examples of things that can be done with it using that old and perennial favourite Northwind Traders. Now the time has come to look at what really can be done in a little more depth. Obviously we’ll continue to make use of the strong design time support that the SEF provides but we’ll also start to use more code behind the scenes. From now on we’ll be looking at a fictional company (AFM (Acme Facilities Management)) based in the UK. They have been running for a couple of years now and whilst establishing themselves they have tended to operate the business on a purely paper based model. Just recently however they have managed to win a contract with a fast food outlet that is itself starting to expand fairly quickly and it has become apparent that the paper based system employed to date simply won’t do.

AFM provide cleaning and maintenance services to their clients, their success is founded upon providing a good, cost effective and reliable service, such that their clients do not need to remember to call them out to attend to routine jobs , AFM always call them a week or so before such jobs require doing and make the necessary arrangements. Whilst AFM when through its initial start-up period this sort of thing was relatively easy to keep track of, a combination of desk diary and a good memory on the part of the company owner serving it well. Now however if standards are to be maintained things are going to need to become more organised.

The initial plan is for a desktop application that can be run in the main office, but an application that will be flexible enough to allow expansion, possibly to a web based form, and almost certainly at some point in the future to one where engineers out in the field wild receive their work tasks electronically and use smart devices to log their work and send the results back to head office.

Because the purpose of this book is to examine the Studio for Entity Framework we will not be going into a lot of detail about the database designed for AFM nor will we be looking at it in its totality, we will however look at sections of it and where relevant explain the reasons why one approach to a particular problem may be preferable to another. What we will say for now though is that it was decided from the outset that this database should allow AFM to keep track of their clients premises (some of whom are companies others are individuals) and the infrastructure therein that AFM are contracted to clean and maintain. Some of the maintenance operations will require that certificates are produced after the event; others will need to be done at regular intervals. AFM may well expand on the number of services offered, so the system will need to be flexible enough to allow for that, and at some point in the future they may opt to amalgamate their financial operations into the system as well. For now however the priority lies in getting an accurate inventory of client’s premises and what’s inside them and also ensuring that routine maintenance gets done in a proper and timely fashion. Initially therefore we’re going to have a database that keeps track of clients and their immediate contact details, the premises that belong to those clients and the inventory within those premises for which AFM have been contracted to provide their services. It will be necessary to keep track of jobs done for a particular client at their premises and also of any certification that may have been issued following the completion of that work. Finally there needs to be a means for AFM to keep track of work that they need to do in the immediate and distant future (an electronic diary).

Now that we have established the basic principles and requirements for our application let’s begin as we did in the introduction by building our basic data model. Plans to expand this application in the future such that it is not restricted to one or two desktop computers in the head office suggest straightway that we should be looking to create a data model that is separate from any application that we build to manipulate the basic user interface. Adopt the same approach that we did earlier in the Getting Started section.

31

Database first or Code first?

Before we begin to examine our application in detail it would be worth taking a brief moment to discuss the merits of database first versus code first where the entity framework is concerned. To begin with let’s make it abundantly clear from the outset that there is no best choice between the two if starting from afresh, it really is a matter of personal preference. If however you may be in the process of converting a legacy application to run against the Entity Framework then in all likelihood there is already an existing database against which you will be working so it makes absolute sense to take the database first approach.

If you have been working with databases for any length of time then you are probably more than familiar with the processes involved in designing a database, and again for you the database first approach is likely to make more sense. Conversely if you are one of those people who like to start a new project / application by creating a whole series of classes to reflect your notion of how things should look then a code first approach is likely to make much more sense.

From a purely personal perspective I’ve been working with databases of one sort or another for years. New applications for me generally start with a large piece of paper on which there will eventually be a lot of boxes with lines between them and a whole sting of scribbled notes to the side that are what in the long term will become business rules and database constraints. Only then do I turn to sql server to actually build the database and create a diagram for it. In actual fact Visio can be a really useful tool to employ for creating a diagram to work with if you happen to have a copy of it.

One other thing that is worth bearing in mind is that there are a large number of database schema for all sorts of basic business scenarios that can be found on the internet. As such a database first approach may well suit you better than a code first approach, which in my opinion at least really suits those people who have that rare ability to be able to ‘see’ through the code and picture what it will eventually look like. I’d rather have the picture very firmly established in my mind first before adding code to it.

It should be made very clear at this point though that the Studio for Entity Framework has no bias one way or the other working equally well with either approach.

The Data Model

The illustration below shows the section of the database that we will be using for our data model. Clearly much more than this would be required for a fully featured business application, but we do at least have enough to be going on with. The one aspect of this that it is worth drawing you attention to at this stage is the Appointments table which is going to provide the ‘electronic diary’ element that AFM now want to have. It will be used to drive a c1Schedule component and its id field isn’t an integer but a globally unique identifier.

32

Contacts PK ContactId

FirstName LastName Telephone Mobile Email Aniversary Memo Engineers PK EngineerId

FirstName LastName Telephone JobTypes Sites Mobile PK JobTypeId PK SiteId Email SubContractor JobDescription SiteName memo Building Number Street Town PostCode SiteMaintenanceJobs PartOf FK1 MainContactId PK JobId

FK4 SiteId InternalWslNo FK3 JobTypeId FK2 AssignedEngineerId Clients ExtinguisherLocations ExtinguisherMaintenanceCertificates DateCalledIn PK ClientId FK1 CalledInById PK,FK1 SiteId PK ExtinguisherCertificateId EstimatedCompletionDate PK ExtinguisherId ActualCompletionDate FK1 SiteId CompanyName AddressTypes FirstName JobCompleted ExtinguisherType CertificateDate LastName PK AddressTypeId JobValue ExtinguisherSize Telephone RecommendationsArising UnitOfMeasurement EMail AddressTypeDescription Manufacturer Location New Rc ExtinguisherCertificateDetails ExtendedServiceDue PK,FK1 ExtinguisherCertificateId PK NumberOfType ClientAddresses PK Type Appointments PK,FK2 ClientId PK Condition PK AppointmentId PK,FK3 SiteId PK DateStarted Recommendation Subject Location FK1 AddressTypeId StartTime DateFinished EndTime Body Properties

Figure 30: The database diagram of the database section to be modelled

In the new project that you have started add a new entity data model targeted against this database. Once you have selected all of the tables that you intend to add to the model go ahead and get the wizard to create it for you. Once that has been done build the project. Now before we go any further we need to make one very important adjustment to the model or else we will find out later on that one rather important part doesn’t work. We mentioned a little earlier that the Appointments table used a Globally Unique Identifier as its primary key. As of version 4.3 the Entity Framework still has problems correctly mapping GUID’s as indent columns.4 To correct this issue a slight amendment needs to be made to the underlying xml that defines the data model that has just been created.

4 You can read a more detailed explanation regarding this in an excellent blog article by Lee Dumond: http://leedumond.com/blog/using-a-guid-as-an-entitykey-in-entity-framework-4/ 33

Figure 31: The Entity Data Model as created by Visual Studio.

If the diagram illustrating the model created by the wizard is still open close it and in the solution explorer right click on the model name and from the context menu select ‘Open With’. From the list of options that you are then presented with, select XML (Text)Editor.

NB. If you haven’t configured visual studio to display line numbers in the xml editor now would be a good time to do so.

When the editor opens scroll down through it to find the SSDL section;

It will be quite close to the top, from there scroll down until you find the section dealing with the appointments entity;

34

Here we see the xml generated for both the AddressTypes table as well as the Appointments table. If you look closely at the line entries dealing with the id fields for each table you will notice a small but subtle difference. For the AddressTypes table xml has been generated to take account of the fact it has an identity field that needs to be automatically generated, but the same is missing for the Appointments table. To correct this we need to add the missing bit to the Appointments section so that it will now look like this;

Make a mental note of the line number in the xml file that you have just altered before you save and close the file. Any time in the future that you refresh or add to the model from the underlying database you will need to make this adjustment. This is something that one hopes will be fixed by Microsoft in forthcoming versions of the Entity Framework but for now it’s a problem that you will need to manually rectify each time you adjust the model.

35

The Entity Model Connection String

With the basic data model completed work can now commence on the main application that AFM will be interacting with on a daily basis. Just as we did before in the Getting Started section we will need to add the data model project to our new project and add a reference to it in the new project’s references. We will also need to copy the connection string section from the data model project’s App.Config file and paste it into the App.Config file of our new project.

At this point it would seem sensible to take a look at the whole issue of connection strings and the Entity Framework.

Entity Framework Connection Strings

Let’s take a look at a typical connection string constructed by the wizard that is invoked when you add an ADO Entity Data Model to a Visual Studio project.

By comparison to standard ADO.net connection strings there appears to be a bit more to this, and indeed there is because in addition to knowing where the server hosting the database is the connection string also needs to record information about where the model definition can be found. There are essentially four parts to this:

1. MetaData; the bit that points to the metadata files. 2. ProviderConnection; the actual connection string to the database. 3. Provider Name; the namespace of database provider. 4. Name; the actual name of the whole Entity Connection String.

During the whole development process this is unlikely to give you any trouble; it will have been constructed referencing your machine and the location of the database that you are working against. In the example string that has been illustrated above you can see that my computer name has been explicitly referenced (PC01\SQLEXPRESS). Now that could be modified to read (.\SQLEXPRESS) which would at least ensure that if the database was residing on a version of SQLEXPRESS then the machine name on which that version was hosted would be academic. The basic assumption that the database engine will be SQLEXPRESS as opposed to a full blown version of SQL Server remains though, and whilst any possibility of ambiguity remains then so too does the possibility of a problem connecting to the database when the application moves from development to production.

One of the most common pitfalls that are encountered by developers when they first start to develop data centric applications is this subtle difference that can exist between a development and production machine. The developed application worked well where it was designed and built, but as soon as it was deployed to a production machine it failed citing some sort of error with the connection to the underlying database. The connection string that the application is referencing in the App.config file is hardcoded to your development environment and unless,

36 somewhat fortuitously the production machine and environment exactly match those of the development machine you are always going to have a problem.

A way needs to be found to correct this anomaly and ideally in such a way as matches the simplicity with which the connection string was originally constructed on the development machine. Fortunately such a way exists.

Creating a dynamic connection string for the SEF

Visual Studio has always possessed a very neat Data Connection wizard but unfortunately it was never licensed for use outside Visual Studio itself, or at least that was the case until February 2010 when Microsoft decided to make the source code freely available5. Even in this freely open form though using it in your own projects still required a little work. The advent of however has changed all that and finally developers have ready and easy access to the Visual Studio Data Connection wizard6. Running one simple command in the nuget Package Manager will ensure that your project ends up with the correct and latest dll’s that are required to make the wizard perform its tricks.

NB: There is one small caveat with using this wizard, your project will need to target the full .net framework 4 not just the client profile.

The next task in hand is to decide on a strategy for building, saving and implementing your dynamic connection string. In truth the decisions you make now are likely to be based on personal preference, all I can do here is offer one approach making no claims that it is the best way, merely one of many approaches that you could take. Personally I would rather that my end user is only ever asked to interact with the data connection wizard once, which implies that it needs to be run the first time that the application is run. It also by definition suggests that once we have established a connection string that works we need to save it somewhere where it can be accessed with ease. One little thing to think about at this stage, in all likelihood on your own development machine you use windows authentication as the means to log onto the database server. Do not assume that this will necessarily be the case in the production environment and plan the way you intend to save the configuration string accordingly.

For me this seemed to suggest utilising the project settings and having given it some consideration my chosen course of action was to be implemented along the following lines:

1. Run the application and perform a check to see if the settings in the project require saving.7 2. Check to see if the setting designated to store the dynamic connection string is empty. 3. If it is empty call the Data Connection dialog and save the resulting connection string the empty setting that we have just looked at. 4. Generate a new entity connection string using the information that we have just obtained from the dialog. 5. Create the global ClientCache that the SEF will use using our newly created connection string as its connection string.

5 See http://archive.msdn.microsoft.com/Connection for more details. 6 See http://nuget.org/packages/DataConnectionDialog/1.2 for more details. 7 Project settings are saved for each version of an application, rather than having to configure them for each new version it is possible to get them moved across if an application has been updated. 37

In terms of code this looks a little like this:

Public ClientCache As EntityClientCache

Public objectcontext As WLSDataEntities

'Carry user settings forward on application upgrade If My.Settings.SettingsUpgraded = False Then My.Settings.Upgrade() My.Settings.SettingsUpgraded = True End If 'Now check to see if there is a value in the setting to be used for storing our new ProviderConnectionString. 'if there isn't we create it and then generate our dynamic connection for the client cache.

If My.Settings.ProviderConnectionString <> String.Empty Then CreateDynamicContextWithConfigurationManager() Else CreateProviderConnectionString() CreateDynamicContextWithConfigurationManager() End If

ClientCache = New EntityClientCache(objectcontext)

The real work is done in the two methods referenced in the If clause above and which are provided in full below.

Private Sub CreateProviderConnectionString() 'This calls the Microsoft DataConnection Wizard.

'first we instantiate the dialog Dim dcd As DataConnectionDialog = New DataConnectionDialog()

'now we limit the dataproviders it could use to just the sql data provider Dim sqlDataSource As DataSource = _ New DataSource("MicrosoftSqlServer", "Microsoft SQL Server") sqlDataSource.Providers.Add(DataProvider.SqlDataProvider) With dcd .DataSources.Add(sqlDataSource) .SelectedDataProvider = DataProvider.SqlDataProvider .SelectedDataSource = sqlDataSource End With

'now we call the dialog and allocate the generated string to the project setting we intend to use to store it If DataConnectionDialog.Show(dcd) = DialogResult.OK Then My.Settings.ProviderConnectionString = dcd.ConnectionString End If End Sub

The code above simply instantiates a new instance of the DataConnectionDialog (you will need to import the Microsoft.Data.ConnectionUI namespace ) and then goes on to limit the data source that it will refer to in order to build the string to that of sql server.

38

Figure 32: The Microsoft Data Connection Dialog configured to only allow SqlClient connections.

The only advantage to be gained from doing that is that it avoids the possibility of the end user selecting the wrong provider. With that done the dialog is shown. The end user can then connect to the server, determine the type of authentication that will allow them to connect, select the database to work against and finally test the connection. By the time that they have clicked OK you should have a working connection string (or to be more exact a working sql client connection string). There is of course absolutely nothing to stop you building this from the ground up, but given that Microsoft now allow you to use this dialog freely you might just as well go ahead and use it.

The next procedure, shown below, sets about building the actual Entity Connection String. We have already seen that that is a very different beast from the more conventional sql connection string that we are used to, but that sql connection string is there. You could try and build this manually but it’s very easy to make stupid little typographic errors. The .net framework provides all the tools that you need so you might as well use them. If you don’t yey have a reference in you project to System.Configuration then now is the time to add one. Begin by using the Sql connection builder to construct a sql connection string. The actual string we have almost in its entirety in one of our project settings (it having made its way there when we called up the DataConnection Dialog). We do need to add one extra bit of information to that though to satisfy the needs of the Entity Framework and that’s the line .MultipleActiveResultsSets = True . 39

Now in most cases the reality is that the only bit that is likely to change in an entity connection string between your deleopment machine and any production machine to which your application is deployed is going to be the Provider connection string (the bit that details the sql server, authentication method and database name). the rest will probably remain the same. Given that it makes sense to use the EntityConnectionStringBuilder to just amend the connection string that sits in the App.Config file with the new provider connection string that we have built using the sqlConnectionStringBuilder. In the second section of the routine that is exactly what we do and then finally we set the objectContext to be application Data Entities constructed from information in the dynamic EntityConnectionString that we have just built.

Private Sub CreateDynamicContextWithConfigurationManager()

'First we use the standard sql connection string builder to build the sql Connection string

Dim sqlBuilder As New SqlConnectionStringBuilder() With sqlBuilder .ConnectionString = My.Settings.ProviderConnectionString .MultipleActiveResultSets = True End With

'then we use the EntityConnectionStringBuilder to finish the job

Dim connectionString = _ ConfigurationManager.ConnectionStrings("WLSDataEntities").ConnectionString Dim connectionStringBuilder = New EntityConnectionStringBuilder(connectionString) _ With {.ProviderConnectionString = sqlBuilder.ToString()}

'Finally we create the object context using our new dynamic connection string

objectcontext = New WLSDataEntities(connectionStringBuilder.ConnectionString)

End Sub

The very last piece of the jigsaw puzzle is to associate the ClientCache that the SEF will use in our application with the objectContext that we have just created in the method above. We do that with one simple line of code;

ClientCache = New EntityClientCache(objectcontext)

The decision by Microsoft to make the Data Connection Dialog readily available for use, combined with the ease with which it can now be added to your projects via nugget has taken all of the hard work out of building dynamic connection strings that you know are going to work.

40

Extending the Data Model

In the getting started section we mentioned that amongst many of the ways that the Studio for Entity Framework extends the Entity Framework was the way in which the C!DataSource added additional properties to grid controls (we used the flexgrid as an example) to help resolve the relationship between tables and return meaningful data. This feature, particularly when used with the flexgrid, makes it very easy to provide auto lookup on certain tables to the end user.

The SEF manages to do this by, in essence, examining the structure of each table and where it finds columns whose name contains either ‘Name’ or ‘Description’ and returning those. In most cases what is returned may very well be sufficient for your needs but as with everything else there will also be times when it isn’t. It’s on these occasions that we can rectify any issues that might arise by extending the Data Model itself and it is this ability to extend the data model that will also help to demonstrate to you why having your Data Model in a separate project makes both good sense and good programing practice.

Our fictitious company had been prompted to computerise its handling of day to day affairs because it had just won a contract with a company that already had a number of sites and was in the process of expanding rapidly itself. One of the first things that they need to do is make an accurate inventory of all the fire fighting equipment at each site that the new company controls. Let’s quickly remind ourselves of what that section of the database as modelled in our data model looks like;

Figure 33: The relationship between Sites and Extinguisher Locations.

41

As things stand in our model the SEF will represent the site relationship in the ExtinguisherLocation entity by using the SiteName field from the Site Entity. So long as every single site has an absolutely unique name this isn’t going to be a problem. Our fictitious company however has just hit its first hurdle in getting this computerisation malarkey to work effectively and aid their efficiency. The new company with whom they have a new contract has its name as the primary part of every site address. If this is applied to the way that they envisioned entering these details on a form then they could well end up with something very similar to that which is illustrated below.

Figure 34: A typical problem that might occur where the same information appears in the field that the SEF uses to resolve relations between tables.

It would be much more useful if the drop down box could display information that uniquely identified each site. In other words what they really want it to display is the site name and address.

Fortunately this can be achieved quite easily by extending the data model. When the Data Model was first built one of the things that it did was to build a lot of boiler plate code behind the scenes that essentially created classes as representations of all the tables within our database. Each one of these classes have properties that equate to the various fields within those tables. What we need to do now is extend those classes to provide us with the information that we require.

NB The syntax used between VB and C# is subtlety different in respect to this none the less the overriding principle and theory remains the same.

Open up the Data Model project in visual studio and add a new class to it. When prompted for a name, call it ‘Site’. As soon as the code window opens make a small but very important addition to the class name. Add the word Partial to it;

42

Partial Public Class Site

When the model was originally built it created a class called ‘Site’, by declaring this new class as ‘Partial’ we are essentially telling the compiler that when all the code that makes up the project is compiled just prior to the program being run that it should amalgamate the code in the original ‘Site’ class that was created by the wizard that built the model with the additional code that we are about to add to this ‘Site’ class. In plain English both sections of code form part of one and the same ‘Site’ class.

It is worth pointing out at this stage that when the data model was created by the wizard those classes that were added as representations of the tables in the underlying database were themselves marked as being ‘Partial’. Technically therefore there is no need to mark our additions to these classes as ‘Partial ‘and I don’t doubt that there will be individuals reading this who do not like to see extraneous information being added to a code file that is technically unnecessary. Personally I take the view that given that these are the only readily visible instances of these classes in the project that can be easily seen within the solution explorer it does no harm to mark them as partial so that others reading the code will know that there are other bits of code relating to them elsewhere.

Now we need to add a new read only property to this class that will essentially concatenate the SiteName, Building, Number and Street fields which ought to be sufficient to provide us with a unique set of site details in each line of the drop down box that we want on our form. Finally to get the SEF to return this new property that we are about to create as opposed to just the SiteName field whenever it resolves the relationship we need to override the ‘ToString’ method of the ‘Site’ class. Your new partial site class should look something like this;

Partial Public Class Site

Public ReadOnly Property sitedetail As String Get Return String.Format("{0} {1} {2} {3}", SiteName, Trim(Building), Trim(Number), Street) End Get End Property

Public Overrides Function ToString() As String Return sitedetail End Function

End Class

The ability to do this also means that we can ensure that the SEF also takes cognisance of some of our business rules. The Clients table has ‘CompanyName, FirstName and LastName fields. These are there to allow for the fact that AFM deal both with companies and individuals, so data entry forms will allow you to enter a company name or a first and last name but not all three. Using the basic rules that SEF does when it decides how to resolve the client relationship means that only the ‘CompanyName’ field will be returned. Quite clearly that’s not going to be of any use any time you want to find an individual in a generic lookup. We can resolve this problem very easily by extending the ‘Client’ class.

43

Partial Public Class Client

Public ReadOnly Property ClientName As String Get If CompanyName IsNot Nothing Then Return CompanyName Else Return String.Format("{0} {1}", FirstName, LastName) End If End Get End Property

Public Overrides Function ToString() As String Return ClientName End Function

End Class

We can also ensure that certain rules are followed each time that new records are added to tables in a similar manner. Within our database there is a table in which maintenance jobs that need to be done at various sites can be entered. Within the table there are fields that record the date the job was first entered into the system and also an estimated completion date. As a general rule AFM aim to complete each job within 14 days of first being informed that it needs to be done. The following addition to the ‘SiteMaintenanceJob’ class ensures that these parameters are automatically set each time a new record is created.

Partial Public Class SiteMaintenanceJob

'''

''' Initializes a new instance of the SiteMaintenanceJob class. ''' Public Sub New() DateCalledIn = Now EstimatedCompletionDate = DateAdd(DateInterval.Day, 14, Now) JobCompleted = False End Sub End Class

As you can see extending the Data Model provides us with some very definite benefits, which are by no means limited to the examples that we have shown here. More importantly though it shows why having the data model in a separate project makes such good sense. We have already mentioned that at some point in the future AFM want to extend this application to be used over the web and possibly on mobile devices as well. As each new variant of the application is prepared, designed and executed for different platforms they will always be able to reference exactly the same data model, which means consistent implementation of fundamental business rules across all platforms.

This is an area to which we will be returning later but for now at least you should have enough information to extend some of the other entity classes so that they either return more useful information when the SEF sets about resolving them in relationship lookups or configure certain key properties when new records are created. As we examine other areas of interaction between the SEF and our application so it will become apparent that adding an extension to the Data Model would make good sense, be it either to impose business rules or to preserve the integrity of the data.

44

Building the first User Interface

You’re planning on building more than one I hear you muse….well not exactly, as with anything else a little planning at this stage can save an awful lot of grief and aggravation later on down the line. It is however the nature of things that ‘needs must’ tends to dictate early decisions so if possible one needs to start off with a solution flexible enough to provide a quick short term solution whilst at the same time allowing it to grow and mature. The SEF is perfectly designed to meet these two apparently diverse goals providing as it does an almost code free ability to get up and running quickly whilst at the same time allowing us to adopt a more structured , coded approach as time permits.

AFM have decided to implement a computerised solution to their anticipated administrative problems caused by having taken on a new client that is itself undergoing rapid expansion. No matter how nice it would be to be in a position to be able to wait until the absolutely perfect solution had been designed and rigorously tested to destruction AFM need to be in a position to use something to fulfil their basic needs as quickly as possible. Fortunately the database itself had been designed long before pressing needs determined that a computerised administrative solution was a necessity so all that would be needed in the short term at least was a quick and robust way to get crucial information recorded and retrieved to enable them to meet their obligations to their clients.

Although we have very pointedly been referring to decisions taken by our fictitious company in truth this is something that is not that far removed from reality. All too often companies will instigate small, frequently bespoke solutions designed to meet pressing needs whilst they are small and growing. They have grown as the company using them has, but all too frequently that organic growth, bolting on additions as they became necessary was not always the most appropriate way to allow an essentially data centric application to evolve. Therein lies the reason that I personally prefer a database first approach. The database design process that ranges from large sheets of paper through to normalisation and eventually to building the database itself and then structuring diagrams from it provides me with a reasonably sound idea of what an application might look like several years down the line even if in the immediate future there are really only plans to implement a small subset of that database to begin with.

Our first application is going to be targeted at standard windows desktops and whilst it would be nice to think that it will come equipped with all the bells and whistles that contribute to a well-rounded application from the outset, the reality is likely to be very different. However a couple of very clear decisions have been made. In light of the fact that there is unlikely to be an absolutely comprehensive help file to accompany the application from the outset8 features that are there should be easily discoverable, this tends to favour the use of a ribbon interface9. There should be a rich selection of tooltips (which can be turned off) and it should be possible to do everything from the keyboard. In the first version at least we will do as much as we can by using the SEF in design mode whilst at the same time endeavouring to ensure that we do not duplicate unnecessary features.

Because the aim of this book is to talk about using the Studio for Entity Framework rather than a book about building an application (which just happens to utilise the SEF) we will not be spending an undue amount of time looking into how to create the necessary forms and classes needed to make everything work but we will look at some of the potentially more interesting things that might be of wider use.

8 In the author’s opinion this is probably the most common mistake made by all application developers. A help file shouldn’t be seen, as it all too often is, as something that it would be nice to include subject to time constraints, but as something that should be there from the outset in as comprehensive a manner as possible. 9 Few things have been as contentious in the world of UI design as the Microsoft Ribbon that was introduced with Office 2007. It is fair to say that it appears to be loved and loathed in equal amounts, but one thing is clear when talking to people about it. Those who were previously very familiar with the office products that gained a ribbon interface hated it because they said that they couldn’t find features that they always used. Those on the other hand who were not truly conversant with Word or Excel found that the ribbon introduced them to features that they hadn’t known existed in the products. Personally I towards the view that the ribbon does aid discoverability and as a result in new applications it is generally my user interface of choice. 45

The priority for AFM at present is to be able to accurately record an inventory of equipment at clients’ sites so that they will be in a position to efficiently carry out routine and emergency maintenance. To that end they will need to record Clients, the various sites that associated with each of their clients and the inventory of equipment that is at each of those sites. AFM also want a way to record jobs that are done at various sites and, where jobs are called in by clients to automatically add them to the centralised electronic appointment planner that AFM now intend to implement.

How to design a database to meet these basic requirements isn’t within the scope of this book suffice to say that the database section (and model resulting from it) that was illustrated earlier meets the basic requirements. Those data entry screens that deal specifically with the clients themselves or details of their individual sites probably lend themselves to forms of a tabular nature. Those on the other hand that are recording what are in effect lists are probably better suited to data grids. In either case there is one key principle of which we should never lose sight, ‘Garbage In, Garbage Out’. Everything that can be done to ensure that the data that is entered is both accurate and valid should be done. Quite how much of that should occur at the form level is open to debate. We have already seen how we can extend the data model to ensure that certain fields are prepopulated with relevant information as a new record is created, and we can also extend the model to take into account business rules and validation. However without doubt it makes sense to validate some things as the data is being entered by the end user and before they attempt to save it.

A little earlier when talking about extending the data model we showed an illustration of a form mock to illustrate why we might want to extend it (see figure 29). That form was not too dissimilar to how we want to layout the form for entering equipment inventories at various sites. If we think back to the part of the data model that deals with sites and the fire extinguishers on those sites (see figure 28) then we can see that that the ExtinguisherLocation entity has a navigation property back to the Site Entity. We could conceivably just have a data grid bound to the ExtinguisherLocation entity, but that means that for each new row we enter we would need to actively specify the site and also that we would end up scrolling through large numbers of records in order to amend particular records. It would be much better if we could select the site that we interested in adding or amending an inventory for from a drop down and then just itemising that inventory in a data grid.

To get the data presented the way that would be most useful to us we’ll add a combo box to the form and beneath that a data grid just as we saw in figure 29. We’ll also add a c1dataSource to the form setting its viewsource to the Site Entity. This means that in addition to the Site Entity we’ll also get access to those Entities with which it has a relationship amongst which is the Entity that we’re really interested in; ExtinguisherLocation. We could add a data navigation control to the form as well allowing us to scroll through the individual records in the site table more easily that accessing them vial the drop down. It wouldn’t be absolutely vital so that would be a choice you make based on personal preference.

It was decided that a FlexGrid would be used to represent the Extinguisher Location entity; this is how it finally ended up in its design view.

Figure 35: The FlexGid configured to enter Extinguisher locations.

46

The Extinguisher Location Entity has the following fields;

Figure 36: Fields in the Extinguisher Locations Table.

In addition to these the Data Model adds the Navigation Property Site (which because of the extension we made to the site Entity in the model will return not just the site name but its address as well. However we already have that detail in the Combo box and the SEF will ensure that the SiteId field is correctly filled when we save any change so there is really no need to have either of those fields in the grid. The rest are in the grid in the order in which they appear in the table, we’ve simply amended the captions to be more meaningful.

You may wonder as to the logic of an integer data type to represent the SiteId but a Decimal Data type to represent the ExtinguisherId. The sole reason for this is that these inventory lists tend to get compiled in such a way as they can act as a route map for engineers to traverse the site as they carry out maintenance work. If at some point additional extinguishers are added they can have a decimal notation (something like 2.1, 2.2 etc) so that when the list is produced in a report sorted on ExtiguisherId they appear in the correct ‘location’.

The next four fields ExtinguisherType, ExtinguisherSize, UnitOfMeasurement and Manufacturer all presented something of an interesting dilemma. They could have been defined as Ids related to reference tables; from there we could have capitalised on the ability of the SEF to provide us with a meaningful lookup in our flexgrid. In reality these would be perfect candidates for enumerations, but at the time of writing this enumerations are still not fully supported in the entity framework (particularly if targeting VB as opposed to c#). Logically there are benefits to have these as enumerations in the future and given that proper support for them is gradually coming to the Entity Framework it makes sense to use an alternative approach in the short term. The FlexGrid will let us define our own lists to act as dropdowns in it and this seems the ideal stance to adopt whilst we await proper enum support.

Fire extinguishers are delineated in litres or kilogrammes depending upon the medium that they contain. It seems logical therefore to automate the selection of the unit of measurement field when the end user selects an extinguisher type. Extinguishers are also only supplied in specific sizes, so again limiting the choice makes sense. This we can achieve within the flexgrid itself relatively easily and illustrated below is a small section of code showing how this might be achieved.

47

Private Sub flex1_AfterEdit(sender As Object, e As C1.Win.C1FlexGrid.RowColEventArgs) Handles flex1.AfterEdit Select Case flex1.Cols(e.Col).Caption Case "Type"

If flex1(e.Row, e.Col) = "Carbon Dioxide" Or flex1(e.Row, e.Col) = "Dry Powder" Then flex1(e.Row, 5) = "Kilogrammes" ElseIf flex1(e.Row, e.Col) = "Fire Blanket" Then flex1(e.Row, 5) = "Sq. Metres" Else flex1(e.Row, 5) = "Litres" End If

End Select End Sub

There is nothing particularly complicated about this, but what is particularly noticeable is that it is quite clearly referencing certain of the flexgrid’s cells by their specific location. If the layout of the grid were to change then these would no longer work.10 Moreover on any occasion that we want to display and retain the ability to amend the contents of the extinguisher locations table through a grid such as the flexgrid this is something that we are going to have to write code to do.

This then might well be better done at the data model level by extending the ExtinguisherLocation Entity. The Entity Framework provides OnPropertyChanging and OnPropertyChanged events to which we can subscribe. Therefore the following ought to do exactly the same:

Partial Public Class ExtinguisherLocation

Private Sub OnExtinguisherTypeChanging(value As String) If value = "Carbon Dioxide" Or value = "Dry Powder" Then UnitOfMeasurement = "Kilogrammes" ElseIf value = "Fire Blanket" Then UnitOfMeasurement = "Sq. Metres" Else UnitOfMeasurement = "Litres" End If End Sub

End Class

The one definite advantage with this is that it does not require us to know exactly where columns are located in the flexgrid so we can move those around at our leisure should we so wish. More importantly any number of forms that we might design and try out in our quest to find the perfect layout will always respect this rule. Of course as with most things in life there is generally a price to be paid. You might think that this is only ever going to be enforced when we create a new record, but in actual fact it is enforced every time that we access the records in Extinguisher Locations. For a relatively small table the performance hit that will be incurred as a result of invoking the OnPropertyChanging event on each record within it is relatively minor, but for a very large record set the

10 Bernardo Castilho (the FlexGrid Master) very correctly pointed out to me whilst proof reading this that technically this could all be done with generic references to the cells in the grid (something akin to this for example; Dim unitColIndex = flex1.Cols("Unit").Index) which would obviate the need to worry about the absolutely specific position of a column in the grid. He is of course entirely correct but this shouldn’t fundamentally alter the decisions we already have, and have yet to make, in respect of whether we do things in the Data Model or in the User Interface. 48 performance hit could be significant. For this particular application the benefits of having this is one place and knowing that we are unlikely to have so many records in the table that the performance hit would be an issue means that it makes sense to extend the data model.

Different types of Fire Extinguisher have different extended service intervals. Again this is something that we can do at the UI level using the events that the flexgrid itself exposes, but as with the example above it would necessitate knowing the exact location (or caption or name of the columns involved). It would seem to be an idea candidate for extending the data model.

The code in the flexgrid would have looked like this (this incidentally is simply another part of the select case statement that we illustrated here Case "New" If flex1(e.Row, 3) = "Carbon Dioxide" Or flex1(e.Row, 3) = "Fire Blanket" Then flex1(e.Row, 10) = flex1(e.Row, e.Col) + 10 Else flex1(e.Row, 10) = flex1(e.Row, e.Col) + 5 End If

Case "Rc" If flex1(e.Row, 3) = "Carbon Dioxide" Then flex1(e.Row, 10) = flex1(e.Row, e.Col) + 10 Else flex1(e.Row, 10) = flex1(e.Row, e.Col) + 5 End If

this could be replaced in the data model with the following:

Private Sub OnNewChanging(value As Integer?) If ExtinguisherType = "Carbon Dioxide" Or ExtinguisherType = "Fire Blanket" Then ExtendedServiceDue = value + 10 Else ExtendedServiceDue = value + 5 End If End Sub

Private Sub OnRcChanging(value As Integer?) If ExtinguisherType = "Carbon Dioxide" Or ExtinguisherType = "Fire Blanket" Then ExtendedServiceDue = value + 10 Else ExtendedServiceDue = value + 5 End If End Sub

Or perhaps more efficiently as:

49

Private Sub OnNewChanging(value As Integer?) ExtendedServiceDue = value + GetExtendedServiceInterval(ExtinguisherType) End Sub

Private Sub OnRcChanging(value As Integer?) ExtendedServiceDue = value + GetExtendedServiceInterval(ExtinguisherType) End Sub

Private Function GetExtendedServiceInterval(ByVal extType As String) As Integer If ExtinguisherType = "Carbon Dioxide" Or ExtinguisherType = "Fire Blanket" Then Return 10 Else Return 5 End If End Function

Extending the model in this way brings with it one more little benefit. You’ll recall that one of the pre requisites for the application was that it should be easy to use for skilled Data Entry personnel for whom the keyboard is king. Retyping data that is the same from row to row is not only a pain but time wasting to boot so it isn’t that difficult to add some code to the flexgrid’s KeyDown event to copy data from the cell above into the cell that currently has the focus. Unfortunately this has the somewhat annoying side effect of not calling the Flexgrid’s After Edit event where we had put some of the code to automatically update the UnitofMeasurement field and the ExtendedServiceDue field. This resulted in having to duplicate the code from the AfterEdit event in our KeyDown Event.

50

Private Sub flex1_KeyDown(sender As Object, e As System.Windows.Forms.KeyEventArgs) Handles flex1.KeyDown If (e.KeyCode = Keys.Insert) Then

flex1(flex1.Row, flex1.Col) = flex1(flex1.Row - 1, flex1.Col)

If flex1.Col = 3 Then

If flex1(flex1.Row, 3) = "Carbon Dioxide" Or flex1(flex1.Row, 3) = "Dry Powder" Then flex1(flex1.Row, 5) = "Kilogrammes" ElseIf flex1(flex1.Row, 3) = "Fire Blanket" Then flex1(flex1.Row, 5) = "Sq. Metres" Else flex1(flex1.Row, 5) = "Litres" End If

ElseIf flex1.Col = 8 Then If flex1(flex1.Row, 3) = "Carbon Dioxide" Or flex1(flex1.Row, 3) = "Fire Blanket" Then flex1(flex1.Row, 10) = flex1(flex1.Row, flex1.Col) + 10 Else flex1(flex1.Row, 10) = flex1(flex1.Row, flex1.Col) + 5 End If

ElseIf flex1.Col = 9 Then If flex1(flex1.Row, 3) = "Carbon Dioxide" Then flex1(flex1.Row, 10) = flex1(flex1.Row, flex1.Col) + 10 Else flex1(flex1.Row, 10) = flex1(flex1.Row, flex1.Col) + 5 End If End If

End If End Sub

Once again this code needs to be specific for the layout of this particular grid, and if any alterations are made to it we need to remember to alter it or it won’t do as we expect. Extending the data model as we have means that we can replace all of that with this;

Private Sub flex1_KeyDown(sender As Object, e As System.Windows.Forms.KeyEventArgs) Handles flex1.KeyDown If (e.KeyCode = Keys.Insert) Then flex1(flex1.Row, flex1.Col) = flex1(flex1.Row - 1, flex1.Col) End If End Sub

A lot neater, completely independent of grid layout and more importantly still, less code in the UI layer to be maintained and clear logic that applies to the data being kept with the data.

There are two other aspects to this particular form and its interaction with the data model that are worthy of mention. In the design for the Extinguisher Locations table (see figure 31) you can see that the ExtinguisherSize column is marked as not allowing nulls. As the column has an integer value each time a new row is instantiated this is given a value of 0. There is a very small range of values that is appropriate and correct for this field and were it possible to have defined them as an enumeration it would have been ideal. Instead we have created a list of values for these in the flexgrid itself. We could create some code to ensure that only those values appropriate to each Extinguisher Type are available as the end user makes their selection but there are so few values to choose from that

51 this seems a little extreme. However we do want to ensure that they do not leave the value as 0. Ideally we want to pick up the fact that they have forgotten to enter a valid value as soon as they try and leave the relevant column on the grid and display a message to that effect. Extending the data model to do this would be a possibility but displaying a message box would require that we reference System.Windows.Forms in our data model, and whilst this would be fine when the data model was being used with UI layers that targeted windows forms it wouldn’t be suitable elsewhere where this was not the case. For this reason we’ll validate this business rule within the UI layer itself calling upon the Flexgrid’s BeforeRowColChange event to do the work for us;

Private Sub flex1_BeforeRowColChange(sender As Object, e As C1.Win.C1FlexGrid.RangeEventArgs) Handles flex1.BeforeRowColChange If flex1.ColSel = 4 Then If flex1.GetData(flex1.RowSel, 4) = 0 Then MessageBox.Show("Please enter a unit size", My.Application.Info.Title, MessageBoxButtons.OK, MessageBoxIcon.Error) e.Cancel = True End If End If End Sub

This does mean that we need to be specific about the location of the column concerned but it’s a price worth paying in this instance.

The next issue concerns the Location Column. Within the database this has been defined as being of type Nvarchar(100) and the fixed limit of 100 characters has been defined in the data model. The Entity Framework (from 4.1 onwards) will validate this for us when it comes to saving records, but if we just leave this to the Entity Framework it will validate the new rows or modified rows when we call saveChanges and if an error is found it simply won’t save any of the changes as they violate a database constraint. More importantly (if we happen to have entered a large number of new rows) it won’t pinpoint exactly on which row (or rows) this violation took place. It would be far more efficient if we caught this particular error at the time that it was made. For that we’ll use the Flexgrid’s ChangeEdit event;

Private Sub flex1_ChangeEdit(sender As Object, e As System.EventArgs) Handles flex1.ChangeEdit Dim text As String = flex1.Editor.Text If text.Length > 100 Then MessageBox.Show("You must restrict the Location Description to 100 characters or less", My.Application.Info.Title, MessageBoxButtons.OK, MessageBoxIcon.Error) End If End Sub

Whilst this particular event is not targeted specifically at the Location column in this case Location is the only field that could conceivably extend to 100 characters so this event, in this case at least, is as good as column specific.

When we began this subsection we stated that our intention was not to concentrate on the actual mechanics of building the application except where it bore a direct relevance to the Studio for Entity Framework. In truth we should perhaps have qualified that a little better and said that we would only discuss matters of user interface design where it had implications for either the Studio for Entity Framework of the Entity Framework in general. Hopefully this has given you a sufficient insight into ways that you can extend the data model to take obvious business logic away from the user interface, but at the same time accepting that a good case can be made for extending the business logic as far as the user interface in areas where it really does make sense to catch an error as quickly as possible.

52

Validating, Saving and the whole business of Transactions

Amongst its many definitions of the word the Oxford English Dictionary defines a Transaction as being the action of passing or making over a thing from one person, thing or state to another. In the context of our discussion then that would refer to the fetching of data from the database and presenting it to us (which hopefully ought to be reasonably straightforward) or sending data from our application back to the database, data that might itself be new or a modification of data which we had already obtained from the database. It is this action of returning data to the database via the conduit of the Entity Framework and the additional tools offered to us by the SEF that we will be examining in this chapter.

Before we go any further let us briefly recap what we have covered up to now. We have seen how easy it is to build an Entity Data Model from an existing database and how we can extend it to provide some basic business rules. We have seen how easy it is to work against that model with the SEF and how it has added some very useful functionality to the basic underlying Entity Framework. We have also looked at how we can provide a dynamic connection string that will allow our application to work properly when deployed to a production environment.

Now we must look to the process of what we should be doing with the data that our end users will enter or modify and the process involved in adding or returning it to the database. In its purest form this can be broken down into a four stage process:

Enter/Amend Data → Validate that Data → Move Data from UI to database → Save that Data to our database

This might be simplified still further to:

User Interface / Data Entities → Transaction → Database

In the terminology that we use when dealing with databases a Transaction is a unit of work (or a collection of new and or amended records if it is easier to envisage it that way) that is either made (or committed to the database) in its entirety or cancelled (not committed to the database) in its entirety thus ensuring that you never make incomplete or inconsistent changes to the Entities.

Basic Validation

Logically then, once we have entered our new data or modified existing data then we need to validate it to ensure its compliance with database constraints or business rules. We have already touched on validation, albeit in a somewhat oblique manner in the previous section. A typical database constraint might suggest that a record can only exist in one table if a corresponding record exists in another table, or that a particular field may not exceed a certain length or should have a given default value. Typical business rules might run along the lines that a sales order detail item may not refer to a product which isn’t currently in stock (Rule: We shouldn’t sell what we don’t have), or that the estimated completion time for a maintenance job that we have been notified needs doing should not be more that fourteen days from the date of notification (Rule: The company policy is that all jobs should have been completed within fourteen days of notification).

As of version 4.1 the Entity Framework can validate our data against those constraints that exist in the database and so by definition are embodied within the Entity Model. This means that if we attempt to send new or modified data back to the database when we call SaveChanges() the data will be validated and should it fail to meet with the 53 constraints that exist the transaction will fail. The Entity Framework will have followed the basic rules about a Transaction implicitly and there will be no underlying inconsistency between the Entities and the Database. If we adopt a strategy of saving our data new or modified row by new or modified row, then arguably there is absolutely no reason not to let the Entity Framework do this for us. Realistically however, we would be more likely to be adding new or modified data in batches so a straightforward failure because we made a mistake with one record’s data would very probably cause us a degree of inconvenience as the failure would simply be just that and whilst it would provide an indication as to why (so long as we had implemented proper error tracking) it wouldn’t tell us where. Such mistakes are best picked up and followed with an appropriate alert as we enter the data. The decision that we need to make is whether this is best done in the data model or in the UI. We have already considered one such example decision in the previous section when discussing the Location field and its constraint that it should be no more than 100 characters in length. Our desire to present the end user with a message box telling them of the error eventually led us to add this validation to the UI rather than the data model.

Let us take a little time to expand on that decision process and then look at another situation where extending the data model makes more sense. The maximum length of the Location field was arrived at because experience had shown that location descriptions rarely exceeded 80 characters in length so building in a 20% allowance for extra information seemed generous and it was unlikely that it would be exceeded. This implies therefore that it’s a rule that the end user is unlikely to remember because it’s one that they would rarely break. A message box that reminds them of the rule that they have just broken seems perfectly acceptable in this instance as they are unlikely to see it that often. Placing the functionality to produce a message box in our Data model would by definition limit the platforms against which it could be targeted so the logical place to catch this error was in the UI.

AFM also have a table in which they record maintenance jobs for each site that they look after. There are three very clear rules that apply to fields in this table. The Estimated completion date needs to be fourteen days after the date that the job was called in to AFM. By default the completed status of a job when first entered onto the system should be false, and when the job is finally done and the actual completion date is entered and the completed status of the job is set to true the actual completion date cannot be set to be earlier than the date the job was called in. Earlier when we first examined extending the data model we added a constructor the the SiteMaintenanceJob Entity to do this for us (see here). There is a fundamental flaw in our logic here. By default we set the date that the job was called in to reflect the date that the record was created, and by extension the estimated completion time for the job is set to be fourteen days later. This may very well be the case most of the time but it won’t always be so. The end user can easily adjust the date that it was called in on the relevant form in which the job is entered and they could probably do the same for the estimated completion date (which by now of course would be wrong) if they noticed that it was incorrect, but that would require them to calculate the necessary time period from the actual date that they have now entered in the called in field. By changing the way we extend the SiteMaintenanceJob Entity we can do this automatically.

Partial Public Class SiteMaintenanceJob

'''

''' Initializes a new instance of the SiteMaintenanceJob class. ''' Public Sub New() DateCalledIn = Now JobCompleted = False End Sub

Private Sub OnDateCalledInChanging(value As Date) EstimatedCompletionDate = DateAdd(DateInterval.Day, 14, value) End Sub End Class

54

Now we have the ensured that the rule about the estimated completion date always being fourteen days from the date that the job was first called in will always be met. It works both when a new record is created but more importantly when the end user changes the value in the date called in field.

The rule relating to the ActualCompletionDate is a little more difficult. You’ll recall that we have to ensure that it is not set to a date prior to the date the job was called in. Do we want to warn the end user that they are entering something that is invalid or do we simply want to ensure that it meets our rule? The action that you take will be determined both by whether you want to issue a warning involving a message box, and perhaps more importantly on whether that particular information will be used elsewhere (perhaps to contribute towards performance statistics and as a result must be accurate). For the time being at least we will extend the entity so that when an actual completion date is entered if it is not later than the called in day we will assume that the job was completed on the day after it was called in. Our extended SiteMaintenanceJob Class will now look like this.

Partial Public Class SiteMaintenanceJob

'''

''' Initializes a new instance of the SiteMaintenanceJob class. ''' Public Sub New() DateCalledIn = Now JobCompleted = False End Sub

Private Sub OnDateCalledInChanging(value As Date) EstimatedCompletionDate = DateAdd(DateInterval.Day, 14, value) End Sub

Private Sub OnActualCompletionDateChanged() Dim val As Date If ActualCompletionDate <= DateCalledIn Then val = DateAdd(DateInterval.Day, 1, DateCalledIn) ActualCompletionDate = val End If End Sub

End Class

There is one small point to note in the above and that is our use of the OnActualCompletionDateChanged() event as opposed to OnActualCompletionDateChanging(Value AS Date). In essence we need in this instance to work after the event (the end user changing the date) rather than during it.

Although we haven’t finished with the whole concept of validation there are some key points related to it that it might be worth summarising now.

 We know that the Entity Framework (from version 4.1 onwards) will take care of validating constraints in the database for us because they are mapped over to the model.  We also know that if it (the Entity Framework) encounters data that does not meet the criteria of a constraint that exists in the model then its default action is to cancel all changes.

From this we can conclude that this behaviour is perhaps acceptable if we only ever work on one record at a time and that the calls made to SaveChanges() are so made as to return any error message that is produced if a problem is encountered. This assumes of course that the end user will understand the message that is returned.

55

 We now know that we can extend the Data Model (and we have by no means covered all the possible ways this can be done) to enforce some basic constraints, business rules and to simply exploit some of the benfits that the SEF brings to the Entity Framework to our advantage.

What we can deduce from this is that the data that we want the Entity Framework to save back to the underlying database for us should be free of simple errors and should not fail any of the constraints that might be imposed upon it by the database. Where possible to perform these checks and validations within the data model it makes sense to do so, but it isn’t unacceptable to bring such validation as far down as the User Interface level if there is a valid reason to so do. An excellent example of that would be spell checking data. Quite clearly that is a user input issue and ought to be dealt with at the source of the error.

As a developer working with the Entity Framework and the SEF (and particularly when working against a database first model) it is your responsibility to ensure that you understand, and allow for, both the constraints that are imposed at the level of the database and any specific business rules that need to be applied to the data. If you succeed in doing your job properly then in theory every call you make to SaveChanges() should always be error free.

Saving the data

Our discussion in this section appears to have been centred on the Entity Framework; you might well be asking yourself at this juncture just where does the Studio for Entity Framework fit in? It is important at this stage to remember that the SEF has been designed to enhance the Entity Framework, not to replace it. The clue is in the name, it’s the Studio for Entity Framework NOT the Studio for ‘some ComponentOne variant of the Entity Framework’. It is crucial that we understand what the Entity Framework is doing, does and the way it reacts when things go wrong. From that understanding we can gain a proper insight into what it is the SEF does to enhance the Framework and how we can best use that to our advantage.

We have alluded to one of the most powerful aspects of the SEF on several occasions throughout this book, now is the time to put that into its true perspective. We have come to the conclusion that we should ensure that all of the data that we add or modify should be properly validated against both existing data constraints and any business rules that there are because of the way that the base Entity Framework effectively saves all or nothing. Let us assume that you have implemented such validation throughout your application.

The real power of the SEF lies in its ability to create a global Client Cache of data (it is possible to achieve the same within the plain Entity Framework but it involves an awful lot of work). In theory you could create an application which at its instantiation uses the SEF to create a global client cache. From then on your end user could work at the application continuously (constantly adding and modifying data at their leisure) and only make one call to SaveChanges() when they finally close it, and everything that they have done, almost as if by magic will find its way back to the database. The global cache of data that the SEF created has kept track of everything, and because you had implemented thorough validation, was in a position to allow the Entity Framework to save absolutely everything back to the database. Just take a couple of moments to ponder on the implications of what it is that you’ve just read, of the remarkable power that the SEF has just handed to you.

With power comes responsibility, and it is to the area of ensuring that you successfully save the data that your end user wants to be saved back to the database that we now turn. We have seen that to save data back to the database with the Entity Framework all that we need do is call ObjectContext.SaveChanges() and with the SEF we would typically call C1DataSource1.ClientCache.SaveChanges(). Any changes that had been made to the ClientCache would then be saved.

56