C Sharp Chapter 16 - ADO PDF
C Sharp Chapter 16 - ADO PDF
NET
This is a largely code-based lesson, showing you how ADO.NET (the data access classes in .NET) is
structured and how to accomplish basic data access in a relational database with C#. ADO.NET takes
its name from ADO (ActiveX Data Objects), a widely used set of classes used for data access in the
previous generation of Microsoft technologies. ADO.NET is the preferred data access interface in
the .NET programming environment.
16. 1 ADO.NET
ADO.NET is the name for the easy-to-use set of classes you use with C# and the .NET Framework to
access, update data in a relational, table-oriented format. This includes relational databases such as
Microsoft SQL Server and Microsoft Access, as well as other databases and even nonrelational data
sources. ADO.NET is integrated into the .NET Framework and is designed for used with any .NET
language. ADO.NET includes all of the System.Data namespace and its nested namespaces such as
System.Data.SqlClient and System.Data.OleDb, plus some specific data-related classes from the
System. Xml namespace. Physically, the ADO.NET classes are contained in the System.Data.dll
assembly and related System.Data.xxx.dll assemblies with some exceptions such as XML.
Extensibility
It provides a framework for plug-in .NET data providers (also called managed providers) that can be
built to read and write data from any data source. ADO.NET comes with several built-in .NET data
providers, including one for the Microsoft SQL Server database, one for Oracle, one each for the
generic database interfaces ODBC (the Microsoft Open DataBase Connectivity database API) and OLE
DB (Microsoft's COM-based Object Linking and Embedding DataBase API). Almost every database and
data file format has an ODBC or OLE DB provider available for it, including Microsoft Access, third-
party databases, and nonrelational data; thus, ADO.NET can be used to interface to almost any
database or data format through one of the built-in data providers. Many database vendors such as
MySQL and Oracle also provide native .NET data providers for their offerings.
ADO.NET uses the open Internet-standard XML format for communications between the tiers, allowing
data to pass through Internet firewalls and allowing the possibility of a non-Microsoft implementation
of one or more tiers.
16 – ADO.Net 1
16.2 Overview of ADO.NET Object Model
Figure 16.1 shows key component classes that are divided into data provider and consumer objects.
Provider Objects
Provider objects are used to read and write the data in memory using the consumer objects. The
provider objects require an active connection. It is prefaced with a provider-specific name unique to each
type of data source (such as, connection object for the OLE DB provider is OleDbConnection; SQL Server .NET
provider is SqlConnection). The following are objects defined in each .NET data provider:
Connection Object. The connection object provides the basic connection to the data source. When using a
database that requires a user and password or one on a remote network server, the connection object
takes care of the details of establishing the connection and logging in.
SqlConnection thisConnection = new SqlConnection(@"Server=(local)\sqlexpress;
Integrated Security=True;" + "Database=northwind");
Command Object. The Command class (Figure 16.2) represents a set-oriented operation that allows
performing any data-manipulation tasks, such as creating and altering tables, database, retrieving,
update and delete of records in a data source. A Command object is used to execute specific SQL
statement/queries that can be inline text or a Stored Procedure against the data source specified in
the Connection Object. You can execute SQL queries to return data in a DataSet or a DataReader
object. To retrieve, add, update and delete data you use SELECT, INSERT, UPDATE, and DELETE SQL
queries, respectively, meeting a certain condition. A DataAdapter generated has these queries.
To create a Command object, you need to create a Connection object that will generate a valid open
connection to the data source. To execute the command, the CreateCommand () method is called. The
CreateCommand () method creates and returns a Command object associated with the Connection
object. It allows the Connection object to automatically create the appropriate provider-specific
Command object.
SqlCommand commandObject = connectionObject.CreateCommand();
commandObject.CommandType = CommandType.Text;
commandObject.CommandText = "Insert Into CustomerFile (CustomerCode, CustomerName)" +
"values(@customerCode ,@customerName)";
commandObject.Parameters.AddWithValue("@customerCode",CustomerCodeTextBox.Text );
commandObject.Parameters.AddWithValue("@customerName",CustomerNameTextBox.Text);
The Command object has a property called CommandText, which contains a String value that
represents the command that will be executed in the Data Source. The CommandType property of a
command object specifies how a CommandText is interpreted, either in Text (default),
StoredProcedure (assign the name of the StoredProcedure to CommandText) or TableDirect.
16 – ADO.Net 2
Alternatively, you can pass the connection argument directly to the Command class as in the following.
OleDbCommand cmd = New OleDbCommand(“Select * from CustomerFile”, connectionObject);
The Command constructor takes two parameters. The first is SQL query and the second is the
Connection object. The Connection Object will generate a valid open connection to the data source and
assign the open connection to the connection property of the Command Object for executing the SQL
statements against a Data Source.
Note: If you have a small amount of data, or are loading all the rows into your DataSet for any other reason, it
makes sense to just use DataTable.Rows.Count. However, if you wanted to count the exact number of rows in a
very large table with 1,000,000 rows, it is much more efficient to issue a SELECT COUNT(*) query with the
ExecuteScalar() method rather than trying to load 1,000,000 rows into memory. It is very useful to use with
aggregate functions ( Count(*),MIN(),MAX(), Sum(),AVG()). ExecuteScalar() uses fewer System resources When
compared to ExecuteReader().
Example: increased all prices by 5 percent for all of its products supplied by the supplier number 12.
SqlCommand command = thisConnection.CreateCommand();
command.CommandText="UPDATE Products SET " + "UnitPrice = UnitPrice*1.05 WHERE
SupplierId=12";
int rowsAffected = thisCommand.ExecuteNonQuery();
if(rowsAffected>0)
Console.WriteLine(“Entries Updated”);
Console.WriteLine("Rows Updated = {0}", rowsAffected);
DataReader Object. The DataReader class (Figure 16.3) provides a pointer based access to the data so
we can get the data in a sequential order. It is used to retrieve data in conjunction with the Command
object to execute a database query (a SQL Select statement). When the query is executed, the first
row is returned to the reader via a data stream. The DataReader object provides the maximum
performance by accessing over the rows in each result set one record at a time and can only move
forward one record at a time in sequential and read-only manner. It requires a live connection with
the data source accessing each column of the result set, read all rows of the set and advance to the
next result set if there are more than one available rows.
16 – ADO.Net 3
The DataReader object cannot be created directly from code, it is created only by binding the
ExecuteReader() method of a Command Object. An open connection must be maintained between
your application and the Data Source through SQL requests. Creating a DataReader with the new
operator doesn't do anything for you. Command object references the connection and the SQL
statement necessary for the DataReader to obtain data.
Features of a DataReader
It is connection oriented architecture and provides faster access to data from a data source.
This is the best choice when the only requirement for a group of data is for reading one time
and you want the fastest method possible.
Doesn't have overhead associated with traversing the data or writing back to the data source.
Appropriate when the need is to simply display the result set, as only one record at a time is
ever present in memory.
The streaming behavior of the DataReader would be a good choice when the amount of data
needed to read is larger than what is preferred to hold in memory beyond a single call, then
It can hold multiple tables at a time. To load multiple tables into a DataReader pass multiple
select statements as the argument to the command separated by a colon (;)
Note: use the NextResult() method of the DataReader object to navigate from the current table to the next table.
Drawbacks of a DataReader
Connection Oriented architecture require/demand a continuous/live connection with the Data
Source to fetch the data, so the performance is decreased if there are a number of clients
accessing the data at the same time.
It gives only forward direction access to data; it allows going to the next record of the table
but not to the previous record of the table.
Where data are not updateable or persist across multiple requests.
using System.Data; // Use ADO.NET namespace reference
using System.Data.SqlClient; // Use SQL Server data provider namespace
SqlConnection is the name of the connection object for the SQL .NET data provider. The connection string consists
of named entries separated by semicolons; let's look at each one. The first is: Server=(=local)\sqlexpress;
This is just the name of the SQL Server you are accessing, in the form computername\instancename. The
computer name (local) is a handy SQL Server shorthand name that refers to the server instance running on the
current machine.
sqlexpress is the SQL Server instance name. Sqlexpress is the default instance name used when you install SQL
Express. If you have another version of SQL Server installed, the instance name will differ — there may be no
instance name (in which case you would use (local) or your machine name by itself), or it may be a different name.
16 – ADO.Net 4
Note that the @ sign prefacing the connection string indicates a string literal, making the backslash in this name
work; otherwise double backslashes (\\) are necessary to escape the backslash character inside a C# string.
The next part of the connection string specifies how to log in to the database; here, you use the integrated security
of the Windows login so no separate user and password need to be specified: Integrated Security=True; This
clause specifies the standard built-in security for SQL Server and Windows. Alternatively, instead of the Integrated
Security clause you could specify a username and password clause, as in User=sa; PWD=secret. Using the built-in
security of your Windows login is preferable to using hard-coded user- names and passwords in connection strings!
Finally, the particular database use is specified, in this case, the Northwind sample: Database = northwind
You must have installed the database to be found. You now have a connection object that is configured for your
machine and database (but the connection is not yet active; to do this you must open it).
2. Open the connection object in order to establishes the connection to the database:
thisConnection.Open(); If the Open() method fails, an exception will be thrown. A particular
message indicates that the program couldn't find the SQL Server database or server. Check that the
server name in the connection string is correct and that the server is running.
To open and close a database connection is an expensive and time-consuming operation. Most
databases have a limit on the number of concurrent connections that they allow. Each connection
consumes a certain amount of resources on the database server and these resources are not infinite.
Most modern OLE DB providers (including SQL Server provider) implement connection pooling. If you
create database connections, they are held in a pool. When you want a connection for an application,
the provider extracts the next available connection from the pool. When your application closes the
connection, it returns to the pool and makes itself available for the next application that wants a
connection.
This means that opening and closing a database connection is no longer an expensive operation. If
you close a connection, it does not mean you disconnect from the database. It just returns the
connection to the pool. If you open a connection, it means it's simply a matter of obtaining an already
open connection from the pool. It's recommended not to keep the connections longer than you need
to. Therefore, you should:
Open a connection when you need it, and
Close it as soon as you have finished with it.
3. Issue a SQL query. Create a command object and give it a SQL statement to perform a database
operation (such as retrieving some data). The code to do this is as follows:
SqlCommand thisCommand = thisConnection.CreateCommand();
thisCommand.CommandText = "SELECT CustomerCode, CustomerName from CustomerFile";
4. Read and display the data. Read the data with a DataReader object. The DataReader is a data
stream returned from a query. To get the data, pull data from a table row-by-row one record at a
time (sequential order). Once a row has been read, the previous row is no longer available. To
read that row again, create a new instance of the DataReader and read through the data stream
again.
SqlDataReader thisReader = thisCommand.ExecuteReader();
When a query is executed, the first row is returned to the reader via the stream. Typical method of
reading the data stream is to iterate through each row with a while loop. The DataReader does not
store the actual data, it only provide some sort of a “pointer” to access the database. The Read()
method of the DataReader will populate with the values of the next available record, and returns true
while there is more data available to read and false otherwise.
while (thisReader.Read())
{
MessageBox.Show("Customer Code " + thisReader["CustomerCode"]+
”\nCustomer Name ” thisReader["CustomerName"]);
}
So, while Read() returns true, you can extract each column of the row in two ways. First, with an ordinal numeric
indexer like, thisReader[0], but it isn't very readable. Second, reference the columns as an array reference by
column name, using a string indexer, thisReader[“CustomerCode”] where the string is the column name from the
SQL query. String indexers are much more readable, making the code easier to maintain. Regardless of the type of
the indexer parameter, a DataReader indexer will return type object. Cast the results to a string type when
necessary. Once the values are extracted, display or store the data in another variable.
5. Close the objects you opened (reader object and connection object).
thisReader.Close();
thisConnection.Close();
16 – ADO.Net 5
Note: You can create OleDbConnection, OleDbCommand, and OleDbDataReader objects. These objects
work essentially the same way as their SQL Server counterparts. Accordingly, change the using
directive that specifies the data provider to System.Data.OleDb;
DataAdapter Object. DataAdapter class (Figure 16.4) is a general-purpose class that provides
communication between a DataSet and a DataSource. This is used to provide an easy way to manage
the connection between your application and the underlying database tables, views and Stored
Procedures. DataAdapter manages the communication between the Dataset and the DataSource with
the help of the Connection Object.
The DataAdapter and DataSet objects are combined to perform both data access and data
manipulation operations in the Database, thus, it provides a disconnected data retrieval mechanism.
It can perform Select, Insert, Update and Delete SQL operations in the Data Source. It uses the Select
statement to fill a DataSet and use the other three SQL commands (Insert, Update, Delete) to
transmit changes back to the Database.
CommandBuilder Object. The CommandBuilder (Figure 16.5) object is used to automatically build SQL
commands for data modification from objects based on a single-table query. It is used to save
changes made in-memory cache of data on backend. The work of CommandBuilder is to generate
command as per changes in DataRows. There is no need to manually code the commands,
CommandBuilder works on add, delete and modified row state only. The CommandBuilder object
generates command on basis of the row state (Unchanged, Added, Deleted, Modified and Detached
(used when object is not created from row state)).
The CommandBuilder opens the Connection associated with the DataAdapter and makes a round trip
to the server each and every time it's asked to construct the action queries. It closes the Connection
when it's done.
Figure 16.5 CommandBuilder Object
16 – ADO.Net 6
Consumer Objects
Consumer objects are used to access and manipulate the data once you have read it into memory.
Consumer objects operate in a disconnected fashion; you can work with the data in memory even if
the database connection is down. These objects aren't related to any specific .NET data provider and
live within the System.Data namespace.
DataSet Object. The DataSet is the king of consumer objects. The DataSet represents a set of
related tables referenced as one unit in your application. For example, Customers, Orders, and
Products might all be tables in one DataSet representing each customer and the products
ordered from a company. With this object, you can get all the data you need from each table
quickly, examine and change it while you're disconnected from the server, and then update
the server with the changes in one efficient operation. The DataSet has features that let you
access lower-level objects that represent individual tables (DataTable) and
relationships(DataRelation).
DataTable Object. This object represents one of the tables in the DataSet, such as Customers,
Orders, or Products. The DataTable object has features that allow you to access its rows and
columns: DataColumn object: This represents one column in the table, for example OrderID or
CustomerName. DataRow object: This represents one row of related data from a table; for
example, a particular customer's CustomerID, name, address, and so on.
DataRelation Object. This object represents the relationship between two tables via a shared
column; for example, the Orders table might have a CustomerID column identifying the
customer who placed the order. A DataRelation object might be created representing the
relationship between Customers and Orders via the shared column CustomerID.
Next, is to reference the .NET data provider for the specific data source to be used.
SQL Server .NET Data Provider. The best performance and most direct access to the underlying
features is available with the native (SQL Server–specific) .NET data provider when SQL
Server database (version 7 or greater) including the desktop engine (SQL Express or MSDE)
used as the data source, referenced with this using directive:
using System.Data.SqlClient;
Oracle .NET Data Provider. If you are using the Oracle database, a native Oracle .NET driver is the
best choice, referenced with this using directive:
using System.Data.OracleClient;
OLE DB .NET Data Provider. OLE DB providers for many common databases are installed with
Windows, notably Microsoft Access as data source, referenced with this using directive:
using System.Data.OleDb;
ODBC .NET Data Provider. If you have a data source for which no native or OLE DB provider is
available, the ODBC .NET data provider is a good alternative because most databases provide
an ODBC interface. It is referenced with this using directive: using System.Data.Odbc;
Many other database vendors and third-party companies provide native .NET data providers; the
choice between using the native provider and using something generic like the ODBC provider will
depend on your circumstances. If you value portability over performance, then go generic. If you want
to get the best performance or make the best use of a particular database's features, go native.
16 – ADO.Net 7
The DataSet object can be Typed or UnTyped and is made up of two objects:
DataTableCollection object contain null or multiple DataTable objects. The DataSet object
has a property named Tables that contains a set of DataTable objects representing the
database tables that you are working within the DataSet.
Each DataTable object has DataRow and DataColumn objects representing the rows and columns of
the database table. You can get to all the individual elements of the tables, rows, and columns
through these objects. DataTable is of type DataTableCollection and has an overloaded indexer, that
you can access each individual DataTable in one of two possible ways:
By table name: thisDataSet.Tables["Customers"] specifies the DataTable called Customers.
By index (zero-based): thisDataSet.Tables[0] specifies the first DataTable in the DataSet.
A DataTable has a Rows property (a collection of the individual DataRow objects. Rows is of type
DataRowCollection), and is an ordered list, indexed by row number.
The DataRow object itself has an indexer property that is overloaded, allowing you to access individual
columns:
by column name: thisDataSet.Tables["Customers"].Rows[n]["CompanyName"];
by index. thisDataSet.Tables["Customers"].Rows[n][0];
thisDataSet specifies the CompanyName column of row number n-1 in the Customers DataTable
of thisDataSet
/*access the individual rows and columns. loop through all the DataRow objects in the Rows collection of the CustomerFile table.
For each DataRow, retrieve the values in the CustomerCode and CustomerName column:*/
foreach (DataRow theRow in thisDataSet.Tables["CustomerFile"].Rows)
{
int row = dataGridView1.Rows.Add();
dataGridView1.Rows[row].Cells[“CustomerCodeColumn”].Value = theRow["CustomerCode"];
dataGridView1.Rows[row].Cells[“CustomerNameColumn”].Value = theRow["CustomerName"];
}
}
Note. You have not explicitly opened or closed a connection in this example — the data adapter takes care of this
for us. The data adapter object will open a connection as needed and close it again once it has finished its work.
The data adapter will leave the state of the connection unchanged — so if the connection was open before the data
adapter started its work, it will be still be open after the data adapter has finished.
if(thisDataSet.Tables[“CustomerFile”].Rows[0][“CustomerCode”])==CustomerCodeTextBox.Text){
thisDataSet.Tables["CustomerFile"].Rows[0]["CustomerName"] = CustomerNameTextBox.Text;
thisAdapter.Update(thisDataSet, "CustomerFile"); // Call Update command to mark changes in the table
MessageBox.Show(“Customer Name is Updated!”);
}
16 – ADO.Net 9
There is no need to worry about the exact SQL syntax for updating the database, all the modifications
to the data in the database can be performed at one time by a CommandBuilder (instead of using
InsertCommand(), UpdateCommand() and DeleteCommand()). Note that you pass thisAdapter to the
SqlCommandBuilder constructor as an argument. The correct SQL commands are generated and
associated with the passed data adapter by the constructor when the SqlCommandBuilder object is
created. The CommandBuilder object takes care of the correct SQL statements for updating
the database. It opens the connection associated with the DataAdapter and makes a round trip to
the servers each and every time it’s asked to construct the action queries. It closes the connection
when it is done.
Now, create your DataSet object (disconnected representation of result sets from data source) and fill
in with data from the query, in this case, it is the CustomerFile table you want, so you call the
associated DataTable in the DataSet by the same name. Now that the DataSet has been filled, you can
access the individual rows and columns.
DataSet thisDataSet = new DataSet();
thisAdapter.Fill(thisDataSet, "CustomerFile");
Validate first the CustomerCode from the input prior to changing the value of a DataColumn:
if(thisDataSet.Tables[“CustomerFile”].Rows[0][“CustomerCode”])==CustomerCodeTextBox.Text)
thisDataSet.Tables["CustomerFile"].Rows[0]["CustomerName"]=CustomerNameTextBox.Text;
However, this change only modifies the value of the column in the DataSet in memory, not in the
database itself. To update the database, you need to call the Update() method, specify the DataSet
you want the update to be based on and the name of the DataTable. It's important that the DataTable
name match the one you used when calling the Fill() method. Like this:
thisAdapter.Update(thisDataSet, "CustomerFile");
The Update() method of the DataAdapter automatically goes through the rows in the
DataTable to check for changes that need to be made to the database. Each DataRow object in
the Rows collection has a RowState property, that keep track whether a row is deleted, added,
modified, or is unchanged. Any changes made are reflected in the database.
4. Persist this change back to the database by calling the Update() method of the data adapter.
//the call to Update() is needed to actually add the new row to the database on disk:
thisAdapter.Update (thisDataSet, "CustomerFile");
Remember, the DataSet is an in-memory, disconnected copy of the data; it is the DataAdapter which
is actually connected to the database on disk and, therefore, its Update() method needs to be called to
synchronize the in-memory data in the DataSet with the database on disk.
Before Find() method can be used, setting up a primary key is a necessity. The primary key is what
you will use when searching. A primary key is made of one or more of the columns of the table
and contains a value or set of values that uniquely identifies this particular row in the table,
so that when you search by the key you will find one and only one row.
16 – ADO.Net 10
Two ways to accomplish a primary key set up:
1. An array of objects that is made from a table with multicolumn primary key.
Create a DataColumn array object — since a table consists of more unique columns, an array
is the natural structure to use;
assign the first element of the array to the field or column name, and the next element field, if
there is another alternate key in the table;
assign the array object to the PrimaryKey property of the DataTable object.
Example: A case with two or more primary fields, we use an array of objects for multicolumn primary key; Find()
method takes an array of objects as parameter. The OrderDetails table in the database uses the ProductID and
OrderID column as its primary keys:
public void SaveButton_Click (. . . . )
{
. . . .
<some codes are omitted for clarity>
thisAdapter.Fill(thisDataSet, "OrderDetails");
// values to be searched
String [] valuesToSearch = new String[2];
valuesToSearch[0]= PoductCodeTextBox.Text;
valuesToSearch[1]= OrderCodeTextBox.Text;
Example: A case for a table with only one primary key column: Find() method takes a single object parameter which is the value you want to look up
public void SaveButton_Click (. . . . )
{
. . . .
<some codes are omitted for clarity>
// Primary key setup by initializing the PrimaryKey property of the DataTable implicitly, simply setup keys object for defining primary key.
thisAdapter.MissingSchemaAction = MissingSchemaAction.AddWithKey;
thisAdapter.Fill(thisDataSet, "CustomerFile"); // Fill DataSet using the query defined for DataAdapter
16 – ADO.Net 11
If findRow is null, go ahead and add the row. When an error message like “The changes you requested
to the table. . . ..” occur, this indicates that the Add() failed because it would have created a duplicate
row. The definition of the table requires that a field contain unique values, which is required when a
column is designated the primary key.
Note. When Delete() is called it doesn't actually remove the row in the database, it just marks it for
deletion until Update is called to commit the change. Each DataRow object in the Rows collection has a
property, RowState, that tracks whether this row is deleted, added, modified, or is unchanged. The
Delete() method sets the RowState of the row to Deleted, and then Update() deletes any rows it finds
in the Rows collection marked as Deleted from the database.
A word of caution about calling the AcceptChanges() method of the DataSet after Delete() — doing so
will remove the row from the DataSet, which means that there will be no effect on the row in the
actual database, because Update() acts only on the rows it finds in the Rows collection, and a missing
row is simply ignored. This same issue applies to the Remove() method; call this only if you want to
remove rows from the Rows collection of the DataSet, but not from the database itself.
Relationships in ADO.NET
The DataRelation object is used to describe the relationships between multiple DataTable objects in a
DataSet. Figure 16.6 shows each row of the OrderFile table contains the CustomerID of the customer
placing the order; you match all the order rows containing a particular CustomerID with that
customer's row in the Customers table. The matching CustomerID fields in the two tables define a
one-to-many relationship (each customer may place several orders) between CustomerFile table and
the OrderFile table. Use this relationship creating a DataRelation object to represent it.
16 – ADO.Net 12
Navigating with Relationships
To use the relationship, navigate from a row of one of the tables to the related rows in the other table.
Often navigations consist of traversing from a parent row in the first table to the related children in
the other table. In Figure 16.6, the row in the CustomerFile table can be considered the parent row
and each of the related rows in the OrderFile table can be considered children. Navigations can also go
in the opposite direction.
For example, with the DataRelation that you created earlier, if the given DataRow in the parent
DataTable (CustomerFile) is customerRow, then customerRow.GetChildRows(custOrderRel);
returns the collection of corresponding DataRow objects from the OrderFile table.
//build DataRelation objects for each of the relationships between the four tables: and link to the dataset
DataRelation custOrderRel =
thisDataSet.Relations.Add("CustOrders",thisDataSet.Tables["CustomerFile"].Columns["Cus
tomerID"],thisDataSet.Tables["OrderFile"].Columns["CustomerID"]);
DataRelation orderDetailRel =
thisDataSet.Relations.Add("OrderDetail",thisDataSet.Tables["OrdersFile"].Columns["Orde
rID"], thisDataSet.Tables["OrderDetails"].Columns["OrderID"]);
DataRelation orderProductRel =
thisDataSet.Relations.Add( "OrderProducts",thisDataSet.Tables["ProductFile"].Columns["
ProductID"], thisDataSet.Tables["OrderDetails"].Columns["ProductID"]);
Next, print out the additional detail of the OrderDate to the OrderID and then get the OrderDetails for
this OrderID. The innermost loop is different; to get the Product row, call GetParentRow(), which gets
the parent object, going from the many side to the one side of the relationship. Sometimes, this
navigation from child to parent is called navigating upstream, as opposed to the normal parent-to-
child downstream navigation. Upstream navigation requires the GetParentRow() call.
16 – ADO.Net 13
16.6 Checkpoint
Name: _________________________________ Schedule: __________________ Date: ______________
General Instructions: Questions/Clarifications should be forwarded to the instructor only. Write your answers
legibly in INK. Accidentally correct answer will not be given credit. Erasures/Alterations are considered wrong.
Academic policy applies. Do not forget to THINK
I. MULTIPLE CHOICE. Encircle the letter that describes best answer.
1. Each row in a database table represents a ________.
A. file B. field C. record D. cell
2. System.Data contains objects used for accessing and storing relational data. Each of these objects
is independent of the type of data source and the way we connect it. Which of these objects are not
part of the System.Data namespace?
A. DataSet B. DataAdapter C. DataTable D. DataRelation
3. The object in ADO.NET handles the execution of SQL statements for the DataReader and
DataAdapter classes.
A. Command B. DataSet C) OLEDB D) Database
4. The DataReader is used for forward-only reading of data. To be able to reuse data from a database,
manipulate the __________ class.
A. ExecuteNonScalar B. ExecuteReader C. DataSet D. DataBase
7. If we are not returning any records from the database which method is used?
A. ExecuteReader () B. ExecuteScalar () C. ExecuteNonQuery() D. ExecuteReaderOnce()
8. Which ADO.Net object has the best performance, for retrieving the data?
A. DataReader B. Data Provider C. DataSet D. DataAdapter
10. You can create a disconnected database access using the _______ class with the dataset class.
A. DataAdapter B. DataReader C. Command D. OleDbConnection
11. When using OleDbConnection, the programmer must close the active connection to the data
source explicitly once no further changes are to be made because,
A. Like DataSets, OleDbCommand objects do not cache data in local memory.
B. Like DataSets, OleDbCommand objects do cache data in local memory.
C. Unlike DataSets, OleDbCommand objects do not cache data in local memory.
D. Unlike DataSets, OleDbCommand objects do cache data in local memory.
13. A program can use instances of class __________ that represents an arbitrary SQL command to
be manipulated on a data source through a(n) _______.
A. CommandText, OleDbCommand B.OleDbCommand, OleDbConnection
C. OleDbCommand, CommandText D. CommandText, OleDbConnection
16 – ADO.Net 14
15. Depending on whether there is a primary key in the DataSet, this method can be used to update
and existing table in a DataSet without changes made to the data in the original data source.
A. Fill B. Update C. FillSchema D. Dispose
16. How many records in memory at any given point of time a the DataReader reads the Data.
A. All records pulled by the reader B. Only one record at a time C. depends on the DataSet
D. Depends on the data provider E. Depends on the data source
17. An object of the class is used to avoid writing additional SQL statements to update a live database.
A. DataReader B. DataSet C. CommandBuilder D. DataGrid
22. A data provider provides a set of components that helps to extract data from the database,
except
A. Connection B. DataSet C. DataReader D. DataAdapter
23. Each DataRelation represents a relationship between two tables through _________ objects.
A. Rows B. DataRow C. DataColumn D. both B and C
24. An alternative to creating a DataSet (and DataAdapter) is to create a __________. This provides
connected, forward-only, read-only access to a collection of tables, by executing either a SQL
statement or stored procedures.
A. DataTable B. Command C. CommandReader D. DataReader
27. When we need to retrieve only a single value from the database, which method is efficient?
A. ExecuteReader() B. ExecuteScalar() C. ExecuteNonQuery() D. ExecuteXmlReader()
28. Opens the connection associated with the DataAdapter object and make round trip to the server
each time it is asked to construct the action queries (build SQL commands).
A. CommandBuilder B. DataReader C. Command D. DataSet
30. The core classes available with each data provider include all the following, except:
A. DataReader B. DataAdapter C. Command D. Dataset
16 – ADO.Net 15
PROJECT DEVELOPMENT
PROJECT OBJECTIVE: To design and implement a Simple Production System.
PROJECT SPECIFICATIONS
1. Database Design
Database Name : PRODUCTION.mdb
Transaction Files
Table Name : JOHeaderFile
Description : Records of the transaction information of the order made by the customer.
Primary Key : JOHNO
Fields Data Type Length Description
JOHNO Long Job Order No.
JOHDATE Date Transaction Date
JOHCUSTNO Text 5 Customer
JOHTOTAMT Currency Total Amount Ordered
JOHPREPBY Text 5 Employee who receives the order (Employee ID)
JOHSTAT Text 2 Order Status
“OP” – Open = the Order is not yet completely delivered
“CL” – Close=Orders Completely delivered
Table Name : JODetailFile
Description : Records of the items bought by the customer.
Primary Key : JODNO + JODPRODCODE
Fields Data Type Length Description
JODNO Long Job Order No.
JODPRODCODE Text 5 Item Code
JODQTYORD Integer Quantity Ordered
JODPRICE Currency Item Price
JODBOMSTAT Text 2 Bill of Materials (BOM) Status
“NC” - BOM not yet generated
“CR” – BOM already generated
JODSTAT Text 2 Ordered Item Status
“OP” – product not yet totally delivered
“CL” – product completely delivered
Table Name : BOMHeaderFile
Description : Keeps the transaction information of the Bill of Materials of a particular product.
Primary Key : BOMHNO
Fields Data Type Length Description
BOMHNO Long BOM Number
BOMHDATE Date Date BOM generated
BOMHJONO Long Job Order No
BOMHPRODCODE Text 5 Product Code
BOMHQTYORD Integer Quantity Billed (Ordered)
BOMHPREPBY Text 5 Employee who prepares BOM
BOMHAPPBY Text 5 Employee who approves BOM
BOMHSTAT Text 2 BOM Status
“OP” – Open (not yet totally purchased /requested)
“CL” – Closed (already purchased/requested)
“CA” – Cancelled
Tablename : BOMDetailFile
Description : Records of the raw materials needed with its corresponding total quantity needed to produce a
particular product.
Primary Key : BOMDNO+BOMDMATCODE
Fields Data Type Length Description
BOMDNO Long BOM Number
BOMDMATCODE Text 5 Raw Material Needed
BOMDQTYNEED Integer Quantity Needed to produce the product
BOMDTOTQTYNEED Integer Total Quantity Needed to produce the product
BOMDQTYRELEASED Integer Quantity Released
BOMDQTYPURCHASED Integer Quantity Purchased
BOMDSTAT Text 2 Material Status
“OP” – Open (material not yet purchased /requested)
“CL” – Closed (material already purchased/requested)
“CA” – Cancelled
16 – ADO.Net 16
Table Name : MaterialReleaseHeaderFile
Description : Records of the transaction information of the materials released from Stockroom/warehouse.
Primary Key : MRHNO
Fields Data Type Length Description
MRHNO Long Material Release No.
MRHDATE Date Release Date
MRHBOMNO Long BOM No
MRHPRODCODE Text 5 Product Code
MRHPREPBY Text 5 Employee who releases the materials
MRHREQBY Text 5 Employee who requests the materials
MRHSTAT Text 2 Release Status
“OP” – Not yet posted/audited
“CL” – Already posted/audited
“CA” – cancelled
Table Name : POHeaderFile
Description : Records of the transaction information of the materials purchase from the supplier.
Primary Key : POHNO
Fields Data Type Length Description
POHNO Long Purchase Order No.
POHDATE Date Transaction Date
POHSUPPNO Text 5 Supplier
POHPREPBY Text 5 Employee who prepares the PO (Employee ID)
POHAPPBY Text 5 Employee who approves the PO (Employee ID)
POHSTAT Text 2 PO Status
“OP” – Open, materials are not yet completely received from supplier
“CL” – Materials Completely received
Table Name : PODetailFile
Description : Records of the materials purchased.
Primary Key : PODNO + PODBOMNO+PODMATCODE
Fields Data Type Length Description
PODNO Long Purchase Order No.
PODBOMNO Long BOM No.
PODMATCODE Text 5 Material Code
PODQTYPURCHASED Integer Quantity Purchased
PODSTAT Text 2 PO Item Status
“OP” – material not yet totally delivered
“CL” – material completely delivered
Reference Files
Table Name : PRODUCTFILE
Description : Records of the products sold by the company.
Primary Key : PRODCODE
Fields Data Type Length Description
PRODCODE Text 5 Product Code
PRODDESC Text 40 Description of the Product
PRODPRICE Currency Price of the Product
PRODUM Text 10 Unit of Measure
PRODSTAT Text 2 Item Status
“AC” – Active
“IN” – Inactive
Table Name : MaterialFile
Description : Records of the raw materials.
Primary Key: MATCODE
Fields Data Type Length Description
MATCODE Text 5 Material Code
MATDESC Text 40 Description of the Material
MATUM Text 10 Unit of Measure
MATQTYONHAND Integer Quantity on Hand
MATQTYADDON Integer Purchase Quantity Add-on
MATSTAT Text 2 Item Status
“AC” – Active
“IN” – Inactive
Table Name : CustomerFile
Description : Records of the customer information.
Primary Key : CUSTNO
Fields Data Type Length Description
CUSTNO Text 5 Customer Account No.
CUSTNAME Text 45 Customer Name
CUSTADDR Text 40 Address
CUSTLIM Currency Customer’s Credit Limit
CUSTBAL Currency Account Balance
CUSTSTAT Text 2 Customer Status
“AC” – Active, “IN” – Inactive
16 – ADO.Net 17
Table Name : ProductMaterialFile
Description : Records of the raw materials needed to produce a product.
Primary Key : PMPRODCODE+PMMATCODE
Fields Data Type Length Description
PMPRODCODE Text 5 Product Code
PMMATCODE Text 5 Material Code
PMQTYNEEDED Integer Quantity Needed to produce a particular product
Material Code Material Description Unit of Measure Quantity Needed Total Quantity Needed
Input: Date, BOM No (must be unique), JO No (must exists in JO File), Product Code (must exists
in JODetailFile), Prepared by code and Approved by codes (must exists in EmployeeFile)
Output: Upon input of the product code, the program will display its corresponding description and
all the materials needed to produce the specified product with its corresponding quantity needed
and total quantity needed
To Save, store required data into BOMHeaderFile and BOMDetailFile
16 – ADO.Net 18
Material Release Entry
MATERIAL RELEASE
Product Code : ___________ Date : ____________
Description : ___________________________ MR No:
BOM No:
-----------------------------------------------------------------------------------------------------------------------------------------------------------
Material Code : ___________ Quantity Released :
Material Code Material Description Unit of Measure Total Quantity Quantity Released
Needed
-----------------------------------------------------------------------------------------------------------------------------------------------------------
BOM No: Material Code :