2. When the app executes, another compiler (known as the just-in-time compiler
22.5 Querying a Database with LINQ
which you can use to get theTitleobjects that represent all the books written by that au- thor. The IDE automatically adds the “s” to “Title” to indicate that this property repre- sents a collection ofTitleobjects. Similarly, theTitle row class contains a navigation property namedAuthors, which you can use to get theAuthorobjects that represent a giv- en book’s authors.
DbContextClass
ADbContext(namespaceSystem.Data.Entity) manages the data flow between the pro- gram and the database. When the IDE generates theentity data model’srow and table class- es, it also creates a derived class of DbContext that is specific to the database being manipulated. For theBooksdatabase, this derived class has properties for theAuthorsand
Titlestables. As you’ll see, these can be used as data sources for manipulating data in LINQ queries and in GUIs. Any changes made to the data managed by theDbContextcan be saved back to the database using theDbContext’sSaveChangesmethod.
IQueryable<T>Interface
LINQ to Entities works through theIQueryable<T>interface, which inherits from the in- terfaceIEnumerable<T>introduced in Chapter 9. When a LINQ to Entities query on an
IQueryable<T>object executes against the database, the results are loaded into objects of the corresponding entity data model classes for convenient access in your code.
Using Extension Methods to ManipulateIQueryable<T>Objects
Recall that extension methods add functionality to an existing class without modifying the class’s source code. In Chapter 9, we introduced several LINQ extension methods, includ- ingFirst,Any,Count,Distinct,ToArrayandToList. These methods, which are defined asstaticmethods of classEnumerable(namespaceSystem.Linq), can be applied to any object that implements theIEnumerable<T>interface, such as arrays, collections and the results of LINQ to Objects queries.
In this chapter, we use a combination of the LINQ query syntax and LINQ extension methods to manipulate database contents. The extension methods we use are defined as
staticmethods of classQueryable(namespaceSystem.Linq) and can be applied to any object that implements theIQueryable<T>interface—these include various entity data model objects and the results of LINQ to Entities queries.
22.5 Querying a Database with LINQ
In this section, we demonstrate how toconnectto a database,queryit anddisplaythe results of the query. There is little code in this section—the IDE providesvisual programming tools andwizardsthat simplify accessing data in apps. These tools establish database con- nections and create the objects necessary to view and manipulate the data through Win- dowsForms GUI controls—a technique known asdata binding.
For the examples in Sections 22.5–22.8, we’ll createonesolution that containsseveral projects. One will be a reusableclass librarycontaining the ADO.NET Entity Data Model for interacting with theBooksdatabase. The other projects will be Windows Forms apps that use the ADO.NET Entity Data Model in the class library to manipulate the database.
Our first example performs a simple query on theBooksdatabase from Section 22.3.
We retrieve the entireAuthorstable, ordered by the authors’ last name, then first name.
We then use data binding to display the data in a DataGridView—a control from namespaceSystem.Windows.Forms that can display data from a data source in tabular format. The basic steps we’ll perform are:
• Create the ADO.NET entity data model classes for manipulating the database.
• Add the entity data model object that represents theAuthorstable as adata source.
• Drag theAuthorstable data source onto theDesignview to create a GUI for dis- playing the table’s data.
• Add code to theForm’s code-behind file to allow the app to interact with the da- tabase.
The GUI for the program is shown in Fig. 22.10.Allof the controls in this GUI are automatically generated when we drag adata sourcethat represents theAuthorstable onto theForminDesignview. TheBindingNavigatortoolbar at the top of the window is a col- lection of controls that allow you to navigate through the records in theDataGridViewthat fills the rest of the window. TheBindingNavigatorcontrols also allow you to add records, delete records, modify existing records and save your changes to the database. You can add a new record by pressing theAdd new( ) button, then entering the new author’s first and last name. You can delete an existing record by selecting an author (either in the
DataGridViewor via the controls on theBindingNavigator) and pressing theDelete( ) button. You can edit an existing record by clicking the first name or last name field for that record and typing the new value. To save your changes to the database, simply click the
Save Data( ) button. Empty values arenotallowed in theAuthors table of theBooks database, so if you attempt to save a record that does not contain a value for both the first name and last name an exception occurs.
22.5.1 Creating the ADO.NET Entity Data Model Class Library
This section presents the steps required to create the entity data model from an existing database. Amodeldescribes the data that you’ll be manipulating—in our case, the data rep- resented by the tables in theBooksdatabase.
Fig. 22.10 | GUI for theDisplay Authors Tableapp.
GUI controls for the BindingNavigator DataGridViewwith theAuthorstable’s column names
Move first
Move previous
Current position Move next
Move last Add new
Delete
Save Data
You can add a new record by typing in this row of the DataGridView
22.5 Querying a Database with LINQ 859
Step 1: Creating a Class Library Project for the ADO.NET Entity Data Model SelectFILE > New Project… to display theNew Projectdialog, then selectClass Library
from theVisual C#templates and name the projectBooksExamples. ClickOKto create the project, then delete theClass1.csfile from theSolution Explorer.
Step 2: Adding the ADO.NET Entity Data Model to the Class Library
To interact with the database, you’ll add an ADO.NET entity data model to the class li- brary project. This will also configure theconnectionto the database.
1. Adding the ADO.NET Entity Data Model. Right click theBooksExamplesproject in theSolution Explorer, then selectAdd > New Item…to display theAdd New Item
dialog (Fig. 22.11). From theDatacategory selectADO.NET Entity Data Modeland name the modelBooksModel.edmx—this file will contain the information about the entity data model you’re about to create. ClickAddto add the entity data model to the class library and display theEntity Data Model Wizarddialog.
2. Choosing the Model Contents. TheChoose Model Contentsstep in theEntity Data Model Wizarddialog (Fig. 22.12) enables you to specify the entity data model’s contents. The model in these examples will consist of data from theBooksdata- base, so selectGenerate from Databaseand clickNext >to display theChoose Your Data Connectionstep.
3. Choosing the Data Connection. In theChoose Your Data Connectionstep, click
New Connection…to display theConnection Properties dialog (Fig. 22.13). (If theChoose Data Source dialog box appears, selectMicrosoft SQL Server, then clickOK.) TheData source:TextBoxshould containMicrosoft SQL Server Data- base File (SqlClient). (If it does not, clickChange…to display a dialog where you can change theData source.) ClickBrowse…to locate and select theBooks.mdf file in theDatabasesdirectory included with this chapter’s examples. You can clickTest Connectionto verify that the IDE can connect to the database through Fig. 22.11 | SelectingADO.NET Entity Data Modelin theAdd New ItemDialog.
SQL Server Express. ClickOKto create the connection. Figure 22.14 shows the
Entity connection stringfor theBooks.mdfdatabase. This string contains the in- formation that the ADO.NET Entity Framework requires to connect to the da- tabase at runtime. ClickNext >. A dialog will appear asking if you’d like to add the database file to your project. ClickYesto move to the next step.
i
Fig. 22.12 | Entity Data Model Wizarddialog’sChoose Model Contentsstep.
i
Fig. 22.13 | Connection Propertiesdialog.
22.5 Querying a Database with LINQ 861
4. Choosing the Database Objects to Include in the Model.In theChoose Your Data- base Objects and Settingsstep, you’ll specify the parts of the database that should be used in the ADO.NET Entity Data Model. Select theTablesnode as shown in Fig. 22.15, then clickFinish.
5. Viewing the Entity Data Model Diagram in the Model Designer. At this point, the IDE creates the entity data model and displays a diagram (Fig. 22.16) in themodel designer. The diagram containsAuthorandTitleentities—these representauthors andtitlesin the database and the properties of each. Notice that the IDE renamed theTitlecolumn of theTitlestable asTitle1to avoid a naming conflict with the classTitlethat represents a row in the table. The line between the entities in- dicates arelationshipbetween authors and titles—this relationship is implemented in theBooksdatabase as theAuthorISBNtable. The asterisk (*) at each end of the line indicates amany-to-many relationship—an author can be an author formany titles and a title can havemanyauthors. TheNavigation Propertiessection in the
Authorentity contains the Titlesproperty, which connects an author to all titles written by that author. Similarly, theNavigation Propertiessection in theTitleen- tity contains theAuthorsproperty, which connects a title to all of its authors.
6. Building the Class Library. SelectBUILD > Build Solutionto build the class library that you’ll reuse in the next several examples—this will compile the entity data model classes that were generated by the IDE. When you build the class library, Fig. 22.14 | Choose Your Data ConnectionstepafterselectingBooks.mdf.
Error-Prevention Tip 22.1
SQL Server Express LocalDB allows only one program at a time to connect to a database file, so ensure that no other program is using the file before connecting to the database.
the IDE generates the classes that you can use to interact with the database. These include a class for each table you selected from the database and a derived class of
DbContextnamedBooksEntitiesthat enables you to programmatically interact with the database. [Note:Building the project causes the IDE to execute a script that creates and compiles the entity data model classes. A security warning dialog appears indicating that this script could harm your computer. ClickOKto allow the script to execute. The warning is intended primarily for cases in which you download from the Internet Visual Studio templates that execute scripts.]
22.5.2 Creating a Windows Forms Project and Configuring It to Use the Entity Data Model
Recall that the next several examples will all be part ofone solutioncontainingseveral proj- ects—the class library project with ourreusable modeland individual WindowsForms apps Fig. 22.15 | Selecting the database’s tables to include in the ADO.NET Entity Data Model.
i
Fig. 22.16 | Entity data model diagram for theAuthorandTitleentities.
22.5 Querying a Database with LINQ 863
for each example. In this section, you’ll create a new WindowsForms app and configure it to be able to use the entity data model that you created in the preceding section.
Step 1: Creating the Project
To add a new Windows Forms project to the existing solution:
1. Right click the solution name inSolution Explorerand selectAdd > New Project…
to display theAdd New Projectdialog.
2. SelectWindows Forms Application, name the projectDisplayTableand clickOK. 3. Change the name of theForm1.cssource file toDisplayAuthorsTable.cs. The IDE updates theForm’s class name to match the source file. Set theForm’sText property toDisplay Authors Table.
4. Configure the solution so that this new project will execute when you select
DEBUG > Start Debugging(or pressF5). To do so, right click theDisplayTable
project’s name in theSolution Explorer, then selectSet as Startup Project. Step 2: Adding a Reference to theBooksExamplesClass Library
To use the entity data model classes for data binding, you must first add areferenceto the class library you created in Section 22.5.1—this allows the new project to use that class library. Each project you create typically contains references to several .NET class libraries (calledassemblies) by default—for example, a WindowsForms project contains a reference to theSystem.Windows.Formslibrary. When you compile a class library, the IDE creates a.dllfile (known as anassembly) containing the library’s components. To add a reference to the class library containing the entity data model’s classes:
1. Right click theDisplayTableproject’sReferencesnode in theSolution Explorer
and selectAdd Reference….
2. In the left column of theReference Managerdialog that appears, selectSolution to display the other projects in this solution, then in center of the dialog select
BooksExamplesand clickOK.BooksExamplesshould now appear in the projects
Referencesnode.
Step 3: Adding References toSystem.Data.EntityandEntityFramework
You’ll also need references to theSystem.Data.EntityandEntityFrameworklibraries to use the ADO.NET Entity Framework. To add a reference toSystem.Data.Entity, repeat Step 2for adding a reference to theBooksExampleslibrary, but in the left column of the
Reference Managerdialog that appears, selectAssembliesthen locateSystem.Data.Entity, ensure that its checkbox is checked and clickOK.System.Data.Entityshould now appear in the projectsReferencesnode.
The EntityFramework library was added by the IDE to the BooksExamples class library project when we created the entity data model, but theEntityFrameworklibrary is also required ineachapp that will use the entity data model. To add a reference to the
EntityFrameworklibrary:
1. Right click the solution name in theSolution Explorerand selectManage NuGet Packages for Solution…to display theManage NuGet Packagesdialog.
2. In the dialog that appears, clickManageto display theSelect Projectsdialog, then select theDisplayTableproject and clickOK.
3. Click Close to close the Manage NuGet Packages dialog. EntityFramework
should now appear in the projectsReferencesnode.
Step 4: Adding the Connection String to the Windows Forms App
Each app that will use the entity data model also requires theconnection stringthat tells the Entity Framework how to connect to the database. The connection string is stored in the
BooksExamplesclass library’sApp.Configfile. In theSolution Explorer, open theBooks-
Examplesclass library’sApp.Configfile then copy lines 7–9, which have the format:
Next, open theApp.Config file in theDisplayTableproject and paste the connection string informationafterthe line containing</entityFramework>andbeforethe line con- taining</configuration>. Save theApp.Configfile.
22.5.3 Data Bindings Between Controls and the Entity Data Model You’ll now use the IDE’s drag-and-drop GUI design capabilities to create the GUI for in- teracting with theBooksdatabase. You must write a small amount of code to enable the autogeneratedGUI to interact with the entity data model. You’ll now perform the steps to display the contents of theAuthorstable in a GUI.
Step 1: Adding a Data Source for theAuthorsTable
To use the entity data model classes for data binding, you must first add them as adata source. To do so:
1. SelectVIEW > Other Windows > Data Sourcesto display theData Sourceswin- dowat the left side of the IDE, then in that window click theAdd New Data Source…link to display theData Source Configuration Wizard.
2. The Entity Data Model classes are used to createobjectsrepresenting the tables in the database, so we’ll use anObjectdata source. In the dialog, selectObjectand clickNext >. Expand the tree view as shown in Fig. 22.17 and ensure thatAuthor is checked. An object of this class will be used as thedata source.
3. ClickFinish.
TheAuthorstable in the database is now a data source from which a data bound GUI control can obtain data. In theData Sourceswindow (Fig. 22.18), you can see theAuthor class that you added in the previous step. Properties representing columns of the database’s
Authorstable should appear below it, as well as aTitlesnavigation property representing the relationship between the database’sAuthorsandTitlestables.
Step 2: Creating GUI Elements
Next, you’ll use theDesignview to create a DataGridViewcontrol that can display the
Authorstable’s data. To do so:
1. Switch toDesignview for theDisplayAuthorsTableclass.
<connectionStrings>
Connection string information appears here
</connectionStrings>
22.5 Querying a Database with LINQ 865
2. Click theAuthornode in theData Sourceswindow—it should change to a drop- down list. Open the drop-down by clicking the down arrow and ensure that the
DataGridViewoption (which is the default) is selected—this is the GUI control that will be used to display and interact with the data.
3. Drag theAuthornode from theData Sourceswindow onto theForminDesignview.
You’ll need to resize theFormto fit theDataGridView.
The IDE creates aDataGridView(Fig. 22.19) with column names representing allthe properties for anAuthor, including theTitlesnavigation property. The IDE also creates aBindingNavigatorthat containsButtons formoving between entries, adding entries, de- leting entries and saving changes to the database. The IDE also generates aBindingSource
(authorBindingSource), which handles the transfer of data between thedata sourceand thedata-bound controlson theForm. Nonvisual components such as theBindingSource
and the non-visual aspects of theBindingNavigatorappear in thecomponent tray—the Fig. 22.17 | Selecting theAuthorclass as the data source.
Fig. 22.18 | Data Sourceswindow showing theAuthorclass as a data source.
gray region below theForminDesignview. The IDE names theBindingNavigatorand
BindingSource (authorBindingNavigator and authorBindingSource, respectively) based on the data source’s name (Author). We use the default names for automatically gen- erated components throughout this chapter to show exactly what the IDE creates.
To make theDataGridViewoccupy theentirewindow below theBindingNavigator, select theDataGridView, then use thePropertieswindow to set theDockproperty toFill. You can stretch the window horizontally to see all theDataGridViewcolumns. We do not use theTitlescolumn in this example, so with theDataGridViewselected, clickEdit Col-
umns…in thePropertieswindow to display theEdit Columnsdialog. SelectTitlesin the
Selected Columnslist, then clickRemoveto remove that column.
Step 3: Connecting the Data Source to theauthorBindingSource
The final step is to connect the data source to theauthorBindingSource, so that the app can interact with the database. Figure 22.20 shows the code needed toobtaindata from the database and tosaveany changes that the user makes to the data back into the database.
Fig. 22.19 | Component tray holds nonvisual components inDesignview.
1 // Fig. 22.20: DisplayAuthorsTable.cs
2 // Displaying data from a database table in a DataGridView.
3 using System;
4 using System.Data.Entity;
5 using System.Data.Entity.Validation;
Fig. 22.20 | Displaying data from a database table in aDataGridView. (Part 1 of 3.)
Objects in the component tray (the gray area below theForm) GUI controls for the BindingNavigator DataGridViewwith theAuthorstable’s column names