Chapter 2. Accessing Data

In This Chapter

  • Understanding the System.Data namespace

  • Connecting to a data source

  • Working with data from databases

Not to predispose you to the contents of this chapter, but you will probably find that data access is the most important part of your use of the .NET Framework. You likely will use the various features of the System.Data namespace more than any other namespace.

Unquestionably, one of the most common uses of Visual Studio is the creation of business applications. Business applications are about data. This is the black and white of development with Visual Studio. While understanding a little of everything is important, complete understanding of the System.Data namespace is essential when you're building business applications.

Until the .NET Framework became popular in the 2003 timeframe, most business applications built using Microsoft products used FoxPro or Visual Basic. C# has unquestionably replaced those languages as the business programmer's language of choice over the past several years.

You can look at the data tools in C# in three ways:

  • Database connectivity: Getting information out of and into a database is a primary part of the System.Data namespace.

  • Holding data in containers within your programs: The DataSet, DataView, and DataTable containers are useful mechanisms for accomplishing the holding of data. If you are a Visual Basic 6 or ASP programmer, you remember Recordsets, which have been replaced by the new constructs.

Note

The Language Integrated Query enables you to get the data out of the data containers using Structured Language Queries (SQL) rather than complicated object-oriented language (OOL).

  • Integration with data controls: The System.Web and System.Windows namespaces function to integrate with the data controls. Data control integration uses database connectivity and data containers extensively. This makes data controls a great target for your reading in this chapter.

Getting to Know System.Data

Data in .NET is different from data in any other Microsoft platform. Microsoft has and continues to change the way data is manipulated in the .NET Framework. ADO.NET, whose implementation is contained in the new data library System.Data, provides yet another new way to think about data from a development perspective:

  • Disconnected: After you get data from a data source, your program is no longer connected to that data source. You have a copy of the data. This cures one problem and causes another:

    • You no longer have a row-locking problem. Because you have a copy of the data, you don't have to constrain the database from making changes.

    • You have the last in wins problem. If two instances of a program get the same data, and they both update it, the last one back to the database overwrites the changes made by the first program.

  • XML driven: The data copy that's collected from the data source is XML under the hood. It might be moved around in a custom format when Microsoft deems it necessary for performance, but it is just XML either way, making movement between platforms or applications or databases much easier.

  • Database-generic containers: The containers don't depend on the type of database at all — they can be used to store data from anywhere.

  • Database-specific adapters: Connections to the database are specific to the database platform, so if you want to connect to a specific database, you need the components that work with that database.

The process for getting data has changed a little, too. You used to have a connection and a command, which returned a Recordset. Now, you have an adapter, which uses a connection and a command to fill a DataSet container. What has changed is the way the user interface helps you get the job done.

System.Data has the classes to help you connect to a lot of different databases and other types of data. These classes are broken up into the namespaces in Table 2-1.

Table 2-1. The System.Data Namespaces

Namespace

Purpose

Most Used Classes

System.Data

Classes common to all of ADO.NET

The containers DataSet, DataView, DataTable, DataRow

System.Data.Common

Utility classes used by database-specific classes

DbCommand, DbConnection

System.Data.ODBC

Classes for connections to ODBC databases such as dBASE

OdbcCommand, OdbcAdapter

System.Data.OleDb

Classes for connections to OleDb databases such as Access

OleDbCommand, OleDbAdapter

System.Data.OracleClient

Classes for connections to Oracle

OracleCommand, OracleAdapter

System.Data.SqlClient

Classes for connections to Microsoft SQL Server

SqlCommand, SqlDataAdapter

System.Data.SqlTypes

For referencing the native types common to SQL Server

SqlDateTime

Though there is a lot to the System.Data namespace and related tools, I focus on the way Visual Studio implements these tools. In previous versions of the development software of all makes and models, the visual tools just made things harder because of the black box problem.

Note

The black box problem is that of having a development environment do some things for you over which you have no control. Sometimes it's nice to have things done for you, but when the development environment doesn't build them exactly how you need them, code is generated that isn't useful.

Fortunately, that isn't the case anymore. Visual Studio now generates completely open and sensible C# code when you use the visual data tools. I think you will be pleased with the results.

How the Data Classes Fit into the Framework

The data classes are all about information storage. In Book I, I talk about collections, which are for storage of information while an application is running. Hashtables are another example of storing information. Collections hold lists of objects, and hashtables hold name and value pairs.

The data containers hold data in larger amounts and help you manipulate that data. Here are the data containers:

  • DataSet: Kind of the granddaddy of them all, the DataSet container is an in-memory representation of an entire database.

  • DataTable: A single table of data stored in memory, the DataTable container is the closest thing you can find to a Recordset, if you are a VB 6 programmer and are looking. DataSet containers are made up of DataTable containers.

  • DataRow: Unsurprisingly, a row in a DataTable container.

  • DataView: A copy of a DataTable that can be used to sort and filter data for viewing purposes.

  • DataReader: A read-only, forward-only stream of data used for one-time processes such as filling up list boxes. Usually called a fire hose.

Getting to Your Data

Everything in the System.Data namespace revolves around getting data from a database such as Microsoft SQL Server and filling these data containers. You can get to this data manually. Generally speaking, the process goes something like this:

  1. You create an adapter.

  2. You tell the adapter how to get information from the database (the connection).

  3. The adapter connects to the database.

  4. You tell the adapter which information to get from the database (the command).

  5. The adapter fills the DataSet container with data.

  6. The connection between the adapter and the database is closed.

  7. You now have a disconnected copy of the data in your program.

Not to put too fine a point on it, but you shouldn't have to go through that process at all. Visual Studio does a lot of the data management for you if you let it, and I recommend that you do.

Using the System.Data Namespace

The System.Data namespace is another namespace that gets mixed up between the code world and the visual tools world. Though it is more of a relationship between the form controls and the Data namespace, it often seems like the data lives right inside the controls, especially when you're dealing with Windows Forms.

In the following sections, you deal primarily with the visual tools, which are as much a part of the C# experience as the code. First, I go over connecting to data sources, and then I show you how to write a quick application using one of those connections. Finally, I go over a little of the code side.

To make all this work, you need to have some kind of schema set up in your database. It can be a local project of your own creation or a sample schema. The next section tells you how.

Setting up a sample database schema

To get started, direct your browser to www.microsoft.com/sqlserver/2005/en/us/express-starter-schemas.aspx. If this URL doesn't work, search the Web for SQL Server 2008 sample schema and find the nearest Microsoft link. It should get you there.

This page offers two sample listings — sample applications and sample schemas. The sample applications are full-blown applications that show complete end-to-end implementation of data-driven software built using .NET. Some are in C#, some are in Visual Basic. The sample schemas are databases only and are designed for database administrators to practice getting experience in handling the system.

Any of the sample schemas will work. If you want exactly the same one as I use in the examples here, choose the Asset Management schema. Other options may be a better fit for the work you're doing. They include

  • Assets Maintenance

  • Contact Management

  • Customers and Orders

  • Document Management

  • e-Commerce

  • Helpdesk

  • Issue Tracking Software

  • Retail Inventory Control

  • Not for Profits

  • Product Catalogs

To install, follow these steps:

  1. Click the Install link to display the familiar Internet Explorer download dialog box. Agree to run the software, and you see a confirmation for the installation. Click Yes to that confirmation, and then agree to the EULA.

    Gotta do the licensing bit!

  2. Pick a destination for the database files. I used c:databases. Agree to create the folder and acknowledge that you did business with Microsoft, and then you should be golden.

    The expanded folder includes four items in the following order: the license that you agreed to, a picture of the database schema, the SQL files for the schema themselves, and an *.mdf file with the schema and the database within.

If you are familiar with SQL Server, you can add a database to your local install and point to it there. In the case that you aren't a DBA, it is also possible to point a data provider directly to a file. That's the angle I take for the rest of this chapter.

Connecting to a data source

There is more to connecting to a database than establishing a simple connection to Microsoft Access these days. Visual Basic developers have to connect to mainframes, text files, unusual databases, Web services, and other programs. All these disparate systems get integrated into windows and Web screens, with update, add, and delete functionality to boot.

Getting to these data sources is mostly dependent on the Adapter classes of the individualized database namespaces. Oracle has its own, as does SQL Server. Databases that are ODBC (Open Database Connectivity) compliant (such as Microsoft Access) have their own Adapter classes; the newer OLEDB (Object Linking and Embedding Database) protocol has one, too.

Fortunately, a wizard handles most of this. The Data Source Configuration Wizard is accessible from the Data Sources panel, where you spend much of your time when working with data. To get started with the Data Source Configuration Wizard, follow these steps:

  1. Start a new Windows Application project by clicking the New Project icon in the Start page. Select a C# Windows Forms Application and give it an appropriate name.

    For this example, I named the Windows Application project Accessing Data.

  2. To open the Data Sources panel, choose Data

    Connecting to a data source

    It should tell you that you have no data sources, as shown in Figure 2-1.

    The Data Sources panel.

    Figure 2-1. The Data Sources panel.

  3. Click the Add New Data Source link in the Data Sources panel.

    This brings up the Data Source Configuration Wizard. The wizard has a variety of data source types that you can choose from. The most interesting of these is the Object source, which gives you access to an object in an assembly to bind your controls to.

  4. Click the Object source type to see the options there, as shown in Figure 2-2. Then click the Previous button to go back to the preceding screen.

    Using an object for a data source.

    Figure 2-2. Using an object for a data source.

    You can pick a Web service to connect to a function on another computer. I cover Web service creation and consumption in Book V, but this functionality sets you up to have a data source along with the Web service reference. It's cool. An example of the blank screen is shown in Figure 2-3.

    Using a Web service for a data source.

    Figure 2-3. Using a Web service for a data source.

    When you finish looking around, click the Cancel button to return.

  5. Click the Database data source type to be taken to the Choose Your Database Model screen.

    For this example, I just used a DataSet. The next part of the wizard is the Choose Your Data Connection screen, as shown in Figure 2-4.

    The most common point of access is a database.

    Choosing your data connection.

    Figure 2-4. Choosing your data connection.

  6. If you have an existing data connection, it appears in the drop-down list. Otherwise, you need to click the New Connection button to bring up the Add Connection dialog box, as shown in Figure 2-5.

    For this example, I click the New Connection button and select Northwind, the Microsoft sample database.

    The Add Connection dialog box.

    Figure 2-5. The Add Connection dialog box.

    The Add Connection dialog box assumes that you are going to connect to a SQL server. If that isn't the case, click the Change button to select a different database from the Change Data Source dialog box, as shown in Figure 2-6. For this example, I chose Microsoft SQL Server Database File and clicked OK.

    The Change Data Source dialog box.

    Figure 2-6. The Change Data Source dialog box.

    If you do use a database file, Visual Studio will copy pertinent files to your project. If you are working through this book in an isolated project, that's fine. If you are on a development effort with others, check to make sure it is appropriate to your life cycle methodology.

  7. Click the Next button to save the connection string to the application configuration file.

  8. Accept the defaults by clicking Next.

    You see the Choose Your Database Objects screen. You can choose the tables, views, or stored procedures that you want to use.

  9. Under Tables, select Parts and Part_Faults (as shown in Figure 2-7), and click Next.

    Selecting data objects.

    Figure 2-7. Selecting data objects.

You're done! If you look at the Data Sources panel, you find that the new data connection was added, as shown in Figure 2-8.

New data connections appear in the Data Sources panel to the left.

Figure 2-8. New data connections appear in the Data Sources panel to the left.

Note

Note that the Data Sources panel has the Parts tables, and the Data Connections panel has all the tables. This is because the DataSet container that you built in the wizard just has the Parts table and related tables in it. The Data Connections panel shows everything in the database.

By following the preceding steps, you create two significant entities in Visual Studio:

  • You create a connection to the database, shown in the Database Explorer. You find that it sticks around — it's specific to this installation of Visual Studio.

  • You also create a project data source, which is specific to this project and won't be there if you start another project.

Both of them are important, and they provide different functionality. In this chapter, I focus on the project-specific data source displayed in the Data Sources panel.

Working with the visual tools

The Rapid Application Development (RAD) data tools for Visual Basic are a massive improvement over what Microsoft previously provided. The RAD data tools in Visual Studio are usable and do what you need, and they write decent code for you.

Note

You need to know that I would never show this kind of black magic if it weren't a best practice. In the past, tools that did something you couldn't see often did their job poorly. Using the tools, in the long run, made your program worse. The new tools, though, are a good way to build software. People may tell you that I am wrong, but it really isn't bad. Try it!

If you click a table in the Data Sources panel, a drop-down arrow appears, as shown in Figure 2-9. Click it and you see something interesting: A drop-down list appears, and you can then choose how that table is integrated into Windows Forms.

Change the Parts table to Details View. It's used to create a detail type form — one that easily enables users to view and change data. Then drag the table to the form, and Details View is created for you, as shown in Figure 2-10.

A whole lot of things happened when you dropped the table on your form:

  • The fields and the field names were added.

  • The fields are in the most appropriate format.

  • The field name is a label.

  • Visual Studio automatically adds a space where the case changes.

Table Options drop-down list.

Figure 2-9. Table Options drop-down list.

Creating a Parts Detail data form.

Figure 2-10. Creating a Parts Detail data form.

Tip

Note that each field gets a SmartTag that enables you to specify a query for the values in the text box. You can also preset the control that's used by changing the values in the Data Sources panel (refer to Figure 2-10).

Also, a VCR Bar (technically called the BindingNavigator) is added to the top of the page. When you run the application, you can use the VCR Bar to cycle among the records in the table.

Finally, four completely code-based objects are added in the Component Tray at the bottom of the page: the DataSet, the BindingSource, the DataAdapter, and the BindingNavigator objects.

Click the Play button and you can see the VCR Bar work. You can walk through the items in the database with no problems, as shown in Figure 2-11. It's just like working in Access or FoxPro, but with enterprise quality!

Running the example.

Figure 2-11. Running the example.

It gets better. Follow these steps to create a child table interface:

  1. Open the Parts table in the Data Sources panel by clicking the plus sign (+) next to the table.

  2. Scroll down until you see the Part FaultsParts table nested in the Orders table.

    Note that this table is in there twice. You want the one under Parts.

  3. Drag that instance of the table over to the form and place it under the Parts fields you placed on the form earlier in this section (refer to Figure 2-10).

  4. Click the Play button to run the example, as shown in Figure 2-12.

You have a running, easy-to-use parent/child form, with parts and part faults. Creating this form would have required you to write a hundred lines of code in other environments. With the capability to choose an assembly for a data source that C# gives you, the form is even nearly enterprise ready. It's slick stuff.

A complete edit form.

Figure 2-12. A complete edit form.

Writing data code

In most enterprise development environments, however, you won't be using the visual tools to build data access software. Generally, an infrastructure is already in place.

The reason for this is that often, enterprise software has specific requirements, and the easiest way to manage those specifications is with unique and customized code. In short, some organizations don't want things done the way Microsoft does them.

Output of the visual tools

The reason that the visual tools often aren't used in enterprise environments is that the code the tools put out is rather sophisticated. If you switch to Code View and right-click an instance of an object (such as the PartsTableAdapter object) and select Go to Definition, you see the code behind the designer.

Figure 2-13 shows what you see when you first get in there. The box marking the region near the top of the code window is marked as Windows Form Designer generated code, and you can't help but notice that the line number before that section is in the twenties and the number after that is in the four hundreds. That's a lot of generated code.

Nothing is wrong with this code, but it is purposely generic to support anything that anyone might want to do with it. Enterprise customers often want to make sure that everything is done the same way. For this reason, they often define a specific data code format and expect their software developers to use that, rather than the visual tools.

Generated code. Huh?

Figure 2-13. Generated code. Huh?

Basic data code

The code of the sample project is simple:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Accessing_Data
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void partsBindingNavigatorSaveItem_Click(object sender, EventArgs
    e)
        {
            this.Validate();
            this.partsBindingSource.EndEdit();
            this.tableAdapterManager.UpdateAll(this.assets_MaintenanceDataSet);

        }
private void Form1_Load(object sender, EventArgs e)
        {
            // TODO: This line of code loads data into the 'assets_
    MaintenanceDataSet.Part_Faults' table. You can move, or remove it, as needed.
            this.part_FaultsTableAdapter.Fill(this.assets_MaintenanceDataSet.
    Part_Faults);
            // TODO: This line of code loads data into the 'assets_
    MaintenanceDataSet.Parts' table. You can move, or remove it, as needed.
            this.partsTableAdapter.Fill(this.assets_MaintenanceDataSet.Parts);

        }
    }
}

While this is fairly straightforward, it obviously isn't everything that you need. The rest of the code is in the file that generates the visual form itself, supporting the visual components.

The time may come when you want to connect to a database without using visual tools. I discuss the steps in the earlier section "How the Data Classes Fit into the Framework," and here I show the code to go with it:

1. SqlConnection mainConnection = new SqlConnection();
2. mainConnection.ConnectionString = "server=(local);database=Assets_
    Maintenance;Trusted_Connection=True"
3. SqlDataAdapter partsAdapter = new SqlDataAdapter("SELECT * FROM
    Parts", mainConnection)
4. DataSet partsDataSet = new DataSet();
5. mainConnection.Open();
6. partsAdapter.Fill(partsDataSet);
7. mainConnection.Close();

Tip

This becomes useful especially when you want to build a Web service or a class library — though it should be noted that you can still use the visual tools in those project types.

Let's talk about this a line at a time. Line one sets up a new data connection, and line two populates it with the connection string. You can get this from your DBA or from the properties panel for the data connection.

Line three has a SQL Query in it. In Chapter 1, I talk about how this is a bad deal, and you should use Stored Procedures. That's true. Don't use inline SQL for production systems. I could have just as easily put a stored procedure name in there.

Line four builds a new dataset. This is where the schema of the returned data is held and what I would use to navigate the data.

Lines 5, 6, and 7 perform the magic: Open the connection, contact the database. Fill the dataset using the adapter, and then close the database. It's all straightforward in this simple example. More complex examples make for more complex code.

After running this code, you would have the Parts table in a DataSet container, just as you did in the visual tools in the earlier section, "How the Data Classes Fit into the Framework." To access the information, you set the value of a text box to the value of a cell in the DataSet container, like this:

TextBox1.Text = myDataSet.Tables[0].Rows[0]["part_name"]

To change to the next record, you need to write code that changes the Rows[0] to Rows[1] in the next example. As you can see, it would be a fair amount of code.

That's why few people use the basic data code to get the databases. Either you use the visual tools or you use a data broker of some sort.

Using the Entity Framework

I don't want to get into much programming philosophy here, but object models (which I discuss in much of this book) and databases just don't go together. They're two different ways of thinking of the same information.

The problem mostly lies in inheritance, which I discuss in Book II. If you have a class called ScheduledEvent, which has certain properties, and a bunch of classes that inherit from it, like Courses, Conferences, and Parties, there just isn't a good way to show this in a relational type of database.

If you make a big table for ScheduledEvents with all possible types of properties, and just make a Type property so you can tell the Courses from the Parties, and then you will have a lot of empty cells. If you make a table for just the properties that are in ScheduledEvents, and then separate tables for Courses and Parties, you make the database remarkably complex.

To address this problem, Microsoft created the Entity Framework. It's the latest edition of a product that Microsoft and everyone else has tried to create since the popularity of relational databases and object-oriented programming made object role modelers necessary.

Object Role Modelers try and take the whole shootin' match and turn it on its head. The goal is to design the database first (which I recommend anyway), and then make an object model to work with it automatically. Then, keep it up to date.

The Entity Framework does an acceptable job at that process. It generates a context for you that you can use to communicate with your data in a way that looks more like an object model than it does a database.

Generating the entity model

To get started, you need the model itself. Just follow these steps to generate the entity model:

  1. Create a new project (I used a Windows Forms project again, called Entity Framework).

  2. Right-click the project and click Add New in the context menu. Select ADO.NET Entity Data Model. Name it PartsDatabase.

  3. Choose Generate from Database Option in the Choose Model Contents window.

  4. Select the Assets_Database.mdf from the Connection drop-down list. If it isn't there, see "Connecting to a data source."

  5. If you get a message asking if you would like to copy the database into the project, select No. Copying the database is usually a bad practice, especially if you are on a shared project. If you are building a standalone project, and are working alone, it is an acceptable solution.

  6. Select the Asset_Parts, Assets, Part_Faults, and Parts tables, just for fun. (See Figure 2-14.) Keep the default name.

    Select a few tables.

    Figure 2-14. Select a few tables.

The next thing you see is the designer canvas for the Class Designer. A sample diagram is shown in Figure 2-15. It's just a class diagram, like the ones in Book II.

Looks like a class model, walks like a database.

Figure 2-15. Looks like a class model, walks like a database.

Notice something missing? The Asset_Parts table is gone; it's been abstracted into the model for you because the table was there only to link the Assets and Parts tables in a many-to-many relationship. Slick, isn't it?

Writing code for the entity model

After you have an interesting addition to your coding environment and the database is meshed nicely into the C# object model, you can code with the objects provided in this new entity model. To start, follow these steps:

  1. Go back to the window designer and double-click on the window to go to Code View.

  2. In the window.load event handler, type Part part = new Part();.

  3. In the next line, type part. and check out the IntelliSense. It contains all columns in the Parts table as properties to the class.

What you now have is a context to work against. No complex Linq queries — they're all done under the covers. No inline SQL. No stored procedures. You can do it all with a scoped object.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.216.138.97