1. How big is the datatype int in .NET?
32 bits.
2. How big is the char?
16 bits (Unicode).
3. How do you initiate a string without escaping each backslash?
Put an @ sign in front of the double-quoted string.
4. What are valid signatures for the Main function?
* public
static void Main()
* public static int Main()
* public static
void Main( string[] args )
* public static int Main(string[] args
)
5. Does Main() always have to be public?
No.
6. How do you initialize a two-dimensional array that you don’t know the dimensions of?
* int [, ]
myArray; //declaration
* myArray= new int [5, 8]; //actual
initialization
7. What’s the access level of the visibility type internal?
Current assembly.
8. What’s the difference between struct and class in C#?
* Structs
cannot be inherited.
* Structs are passed by value, not by
reference.
* Struct is stored on the stack, not the
heap.
9. Explain encapsulation.
The implementation is hidden, the interface is exposed.
10. What data type should you use if you want an 8-bit value that’s signed?
sbyte.
11. Speaking of Boolean data types, what’s different between C# and C/C++?
There’s no conversion between 0 and false, as well as any other number and true, like in C/C++.
12. Where are the value-type variables allocated in the computer RAM?
Stack.
13. Where do the reference-type variables go in the RAM?
The references go on the stack, while the objects themselves go on the heap. However, in reality things are more elaborate.
14. What is the difference between the value-type variables and reference-type variables in terms of garbage collection?
The value-type variables are not garbage-collected, they just fall off the stack when they fall out of scope, the reference-type objects are picked up by GC when their references go null.
15. How do you convert a string into an integer in .NET?
Int32.Parse(string), Convert.ToInt32()
16. How do you box a primitive data type variable?
Initialize an object with its value, pass an object, cast it to an object
17. Why do you need to box a primitive variable?
To pass it by reference or apply a method that an object supports, but primitive doesn’t.
18. What’s the difference between Java and .NET garbage collectors?
Sun left the implementation of a specific garbage collector up to the JRE developer, so their performance varies widely, depending on whose JRE you’re using. Microsoft standardized on their garbage collection.
19. How do you enforce garbage collection in .NET?
System.GC.Collect();
20. Can you declare a C++ type destructor in C# like ~MyClass()?
Yes, but what’s the point, since it will call Finalize(), and Finalize() has no guarantees when the memory will be cleaned up, plus, it introduces additional load on the garbage collector. The only time the finalizer should be implemented, is when you’re dealing with unmanaged code.
21. What’s different about namespace declaration when comparing that to package declaration in Java?
No semicolon. Package declarations also have to be the first thing within the file, can’t be nested, and affect all classes within the file.
22. What’s the difference between const and readonly?
You can
initialize readonly variables to some runtime values. Let’s say your
program uses current date and time as one of the values that won’t
change. This way you declare
public readonly string DateT = new
DateTime().ToString().
23. Can you create enumerated data types in C#?
Yes.
24. What’s different about switch statements in C# as compared to C++?
No fall-throughs allowed.
25. What happens when you encounter a continue statement inside the for loop?
The code for the rest of the loop is ignored, the control is transferred back to the beginning of the loop.
26. Is goto statement supported in C#?
How about Java? Gotos are supported in C#to the fullest. In Java goto is a reserved keyword that provides absolutely no functionality.
27. Describe the compilation process for .NET code?
Source code is compiled and run in the .NET Framework using a two-stage process. First, source code is compiled to Microsoft intermediate language (MSIL) code using a .NET Framework-compatible compiler, such as that for Visual Basic .NET or Visual C#. Second, MSIL code is compiled to native code.
28. Name any 2 of the 4 .NET authentification methods.
ASP.NET,
in conjunction with Microsoft Internet Information Services (IIS), can
authenticate user credentials such as names and passwords using any of
the following authentication methods:
* Windows: Basic, digest, or
Integrated Windows Authentication (NTLM or Kerberos).
* Microsoft
Passport authentication
* Forms authentication
* Client
Certificate authentication
29. How do you turn off SessionState in the web.config file?
In the
system.web section of web.config, you should locate the httpmodule tag
and you simply disable session by doing a remove tag with attribute
name set to session.
30. What is main difference between Global.asax and Web.Config?
ASP.NET uses the global.asax to establish any global objects that your Web application uses. The .asax extension denotes an application file rather than .aspx for a page file. Each ASP.NET application can contain at most one global.asax file. The file is compiled on the first page hit to your Web application. ASP.NET is also configured so that any attempts to browse to the global.asax page directly are rejected. However, you can specify application-wide settings in the web.config file. The web.config is an XML-formatted text file that resides in the Web site’s root directory. Through Web.config you can specify settings like custom 404 error pages, authentication and authorization settings for the Web site, compilation options for the ASP.NET Web pages, if tracing should be enabled, etc.
ASP.NET interview questions
Q1 # Describe the role of inetinfo.exe, aspnet_isapi.dll andaspnet_wp.exe
in the page
loading process. inetinfo.exe is theMicrosoft IIS server running,
handling ASP.NET requests among other things.When an ASP.NET
request is received
(usually a file with .aspx extension),the
ISAPI filter aspnet_isapi.dll takes
care of it by passing the
request tothe actual worker process aspnet_wp.exe.
Q2 # What’s the difference between Response.Write() andResponse.Output.Write()?
The latter one allows you to write formattedoutput.
Q3 # What methods are fired during the page load?
nit() - when the page is instantiated, Load() - when the page is loaded into server memory, PreRender() - the brief moment before the page is displayed to the user asHTML,
Unload() - when page finishes loading.
Q4 # Where does the Web page belong in the .NET Framework class hierarchy?
System.Web.UI.Page
Q5 # Where do you store the information about the user’s locale?
System.Web.UI.Page.Culture
Q6 # What’s the difference between Codebehind="MyCode.aspx.cs" andSrc="MyCode.aspx.cs"?
CodeBehind is relevant to Visual Studio.NET only.
Q7 # What’s a bubbled event?
When you have a complex control, likeDataGrid, writing an event processing routine for each object (cell, button,row, etc.) is quite tedious. The controls can bubble up their eventhandlers, allowing the main DataGrid event handler to take care of itsconstituents.
Q8 # Suppose you
want a certain ASP.NET function executed on MouseOver overa
certain button. Where do you add an event handler?
t’s the
Attributesproperty, the Add function inside that property. So
btnSubmit.Attributes.Add("onMouseOver","someClientCode();")
A
simple”Javascript:ClientCode();” in the button control of the
.aspx page will attach the handler (javascript function)to the
onmouseover event.
Q9 # What data type does the RangeValidator control support?
Integer,String and Date.
Q10 # Where would
you use an iHTTPModule, and what are the limitations of any
approach you might take in implementing one?
One of
ASP.NET’s most useful features is the extensibility of the HTTP
pipeline, the path that data takes between client and server. You can
use them to extend your ASP.NET applications by adding pre- and
post-processing to each HTTP request coming into your application. For
example, if you wanted custom authentication facilities for your
application, the best technique
would be to intercept the request
when it comes in and process the request in a custom HTTP
module.
Q11 # Explain what a diffgram is, and a good use for one?
A DiffGram is
an XML format that is used to identify current and original
versions of data elements. The DataSet uses the DiffGram format to
load and persist its contents, and to serialize its contents for
transport across a network connection. When a DataSet is written as a
DiffGram, it populates the DiffGram with all the necessary information
to accurately recreate the contents, though not the
schema, of the
DataSet, including column values from both the Original and Current
row versions, row error information, and row order.
ADO.NET
This lesson is an
introduction to ADO.NET. It introduces primary ADO.NET concepts and
objects that you will learn about in later lessons. Here are the
objectives of this lesson:
· Learn what ADO.NET is.
·
Understand what a data provider is.
· Understand what a connection
object is.
· Understand what a command object is.
· Understand
what a DataReader object is.
· Understand what a DataSet object
is.
· Understand what a DataAdapter object
is.
Introduction
ADO.NET is an object-oriented set of libraries
that allows you to interact with data sources. Commonly, the data
source is a data base, but it could also be a text file, an Excel
spread sheet, or an XML file. For the purposes of this tutorial, we
will look at ADO.NET as a way to interact with a data base.
As you
are probably aware, there are many different types of data bases
available. For example, there is Microsoft SQL Server, Microsoft
Access, Oracle, Borland Interbase, and IBM DB2, just to name a few. To
further refine the scope of this tutorial, all of the examples will
use SQL Server.
Data Providers
We know that ADO.NET allows us
to interact with different types of data sources and different types
of data bases. However, there isn't a single set of classes that allow
you to accomplish this universally. Since different data sources
expose different protocols, we need a way to communicate with the
right data source using the right protocol. Some older data sources
use the ODBC protocol, many newer data sources use the OleDb protocol,
and there are more data sources every day that allow you to
communicate with them directly through .NET ADO.NET class libraries.
ADO.NET provides a relatively common way to interact with data
sources, but comes in different sets of libraries for each way you can
talk to a data source. These libraries are called Data Providers and
are usually named for the protocol or data source type they allow you
to interact with. table 1 lists some well known data providers, the
API prefix they use, and the type of data source they allow you to
interact with.
table 1. ADO.NET Data Providers are class libraries
that allow a common way to interact with specific data sources or
protocols. The library APIs have prefixes that indicate which provider
they support.
Provider Name API prefix Data Source
Description
ODBC Data Provider Odbc Data Sources with an ODBC
interface. Normally older data bases.
OleDb Data Provider OleDb
Data Sources that expose an OleDb interface, i.e. Access or
Excel.
Oracle Data Provider Oracle For Oracle Data Bases.
SQL
Data Provider Sql For interacting with Microsoft SQL
Server.
Borland Data Provider Bdp Generic access to many data bases
such as Interbase, SQL Server, IBM DB2, and Oracle.
An example may
help you to understand the meaning of the API prefix. One of the first
ADO.NET objects you'll learn about is the connection object, which
allows you to establish a connection to a data source. If we were
using the OleDb Data Provider to connect to a data source that exposes
an OleDb interface, we would use a connection object named
OleDbConnection. Similarly, the connection object name would be
prefixed with Odbc or Sql for an OdbcConnection object on an Odbc data
source or a SqlConnection object on a SQL Server data base,
respectively. Since we are using MSDE in this tutorial (a scaled down
version of SQL Server) all the API objects will have the Sql prefix.
i.e. SqlConnection.
ADO.NET Objects
ADO.NET includes many
objects you can use to work with data. This section introduces some of
the primary objects you will use. Over the course of this tutorial,
you'll be exposed to many more ADO.NET objects from the perspective of
how they are used in a particular lesson. The objects below are the
ones you must know. Learning about them will give you an idea of the
types of things you can do with data when using ADO.NET.
The
SqlConnection Object
To interact with a data base, you must have a
connection to it. The connection helps identify the data base server,
the data base name, user name, password, and other parameters that are
required for connecting to the data base. A connection object is used
by command objects so they will know which data base to execute the
command on.
The SqlCommand Object
The process of interacting
with a data base means that you must specify the actions you want to
occur. This is done with a command object. You use a command object to
send SQL statements to the data base. A command object uses a
connection object to figure out which data base to communicate with.
You can use a command object alone, to execute a command directly, or
assign a reference to a command object to an SqlDataAdapter, which
holds a set of commands that work on a group of data as described
below.
The SqlDataReader Object
Many data operations require
that you only get a stream of data for reading. The data reader object
allows you to obtain the results of a SELECT statement from a command
object. For performance reasons, the data returned from a data reader
is a fast forward-only stream of data. This means that you can only
pull the data from the stream in a sequential manner. This is good for
speed, but if you need to manipulate data, then a DataSet is a better
object to work with.
The DataSet Object
DataSet objects are
in-memory representations of data. They contain multiple Datatable
objects, which contain columns and rows, just like normal data base
tables. You can even define relations between tables to create
parent-child relationships. The DataSet is specifically designed to
help manage data in memory and to support disconnected operations on
data, when such a scenario make sense. The DataSet is an object that
is used by all of the Data Providers, which is why it does not have a
Data Provider specific prefix.
The SqlDataAdapter
Object
Sometimes the data you work with is primarily read-only and
you rarely need to make changes to the underlying data source. Some
situations also call for caching data in memory to minimize the number
of data base calls for data that does not change. The data adapter
makes it easy for you to accomplish these things by helping to manage
data in a disconnected mode. The data adapter fills a DataSet object
when reading the data and writes in a single batch when persisting
changes back to the data base. A data adapter contains a reference to
the connection object and opens and closes the connection
automatically when reading from or writing to the data base.
Additionally, the data adapter contains command object references for
SELECT, INSERT, UPDATE, and DELETE operations on the data. You will
have a data adapter defined for each table in a DataSet and it will
take care of all communication with the data base for you. All you
need to do is tell the data adapter when to load from or write to the
data base.
Summary
ADO.NET is the .NET technology for
interacting with data sources. You have several Data Providers, which
allow communication with different data sources, depending on the
protocols they use or what the data base is. Regardless, of which Data
Provider used, you'll use a similar set of objects to interact with a
data source. The SqlConnection object lets you manage a connection to
a data source. SqlCommand objects allow you to talk to a data source
and send commands to it. To have fast forward-only read access to
data, use the SqlDataReader. If you want to work with disconnected
data, use a DataSet and implement reading and writing to/from the data
source with a SqlDataAdapter.
Lesson 02: The SqlConnection
Object
This lesson describes the SqlConnection object and how to
connect to a data base. Here are the objectives of this lesson:
·
Know what connection objects are used for.
· Learn how to
instantiate a SqlConnection object.
· Understand how the
SqlConnection object is used in applications.
· Comprehend the
importance of effective connection lifetime
management.
Introduction
The first thing you will need to do
when interacting with a data base is to create a connection. The
connection tells the rest of the ADO.NET code which data base it is
talking to. It manages all of the low level logic associated with the
specific data base protocols. This makes it easy for you because the
most work you will have to do in code is instantiate the connection
object, open the connection, and then close the connection when you
are done. Because of the way that other classes in ADO.NET are built,
sometimes you don't even have to do that much work.
Although
working with connections is very easy in ADO.NET, you need to
understand connections in order to make the right decisions when
coding your data access routines. Understand that a connection is a
valuable resource. Sure, if you have a stand-alone client application
that works on a single data base one one machine, you probably don't
care about this. However, think about an enterprise application where
hundreds of users throughout a company are accessing the same data
base. Each connection represents overhead and there can only be a
finite amount of them. To look at a more extreme case, consider a Web
site that is being hit with hundreds of thousands of hits a day.
Applications that grab connections and don't let them go can have
seriously negative impacts on performance and scalability.
Creating
a SqlConnection Object
A SqlConnection is an object, just like any
other C# object. Most of the time, you just declare and instantiate
the SqlConnection all at the same time, as shown
below:
SqlConnection conn = new SqlConnection(
"Data
Source=(local);Initial Catalog=Northwind;Integrated
Security=SSPI");
The SqlConnection object instantiated above uses a
constructor with a single argument of type string. This argument is
called a connection string. table 1 describes common parts of a
connection string.
table 1. ADO.NET Connection Strings contain
certain key/value pairs for specifying how to make a data base
connection. They include the location, name of the database, and
security credentials.
Connection String Parameter Name
Description
Data Source Identifies the server. Could be local
machine, machine domain name, or IP Address.
Initial Catalog Data
base name.
Integrated Security Set to SSPI to make connection with
user's Windows login
User ID Name of user configured in SQL
Server.
Password Password matching SQL Server User
ID.
Integrated Security is secure when you are on a single machine
doing development. However, you will often want to specify security
based on a SQL Server User ID with permissions set specifically for
the application you are using. The following shows a connection
string, using the User ID and Password parameters:
SqlConnection
conn = new SqlConnection(
"Data Source=DatabaseServer;Initial
Catalog=Northwind;User
ID=YourUserID;Password=YourPassword");
Notice how the Data Source
is set to DatabaseServer to indicate that you can identify a data base
located on a different machine, over a LAN, or over the Internet.
Additionally, User ID and Password replace the Integrated Security
parameter.
Using a SqlConnection
The purpose of creating a
SqlConnection object is so you can enable other ADO.NET code to work
with a data base. Other ADO.NET objects, such as a SqlCommand and a
SqlDataAdapter take a connection object as a parameter. The sequence
of operations occurring in the lifetime of a SqlConnection are as
follows:
1. Instantiate the SqlConnection.
2. Open the
connection.
3. Pass the connection to other ADO.NET objects.
4.
Perform data base operations with the other ADO.NET objects.
5.
Close the connection.
We've already seen how to instantiate a
SqlConnection. The rest of the steps, opening, passing, using, and
closing are shown in Listing 1.
Listing 1. Using a
SqlConnection
using System;
using System.Data;
using
System.Data.SqlClient;
///
/// Demonstrates how to work
with SqlConnection objects
///
class
SqlConnectionDemo
{
static void Main()
{
// 1. Instantiate
the connection
SqlConnection conn = new SqlConnection(
"Data
Source=(local);Initial Catalog=Northwind;Integrated
Security=SSPI");
SqlDataReader rdr =
null;
try
{
// 2. Open the
connection
conn.Open();
// 3. Pass the connection to a
command object
SqlCommand cmd = new SqlCommand("select * from
Customers", conn);
//
// 4. Use the
connection
//
// get query results
rdr =
cmd.ExecuteReader();
// print the CustomerID of each
record
while
(rdr.Read())
{
Console.WriteLine(rdr[0]);
}
}
finally{
// close the reader
if (rdr !=
null)
{
rdr.Close();
}
// 5. Close the
connection
if (conn !=
null)
{
conn.Close();
}
}
}
}
As shown in Listing
1, you open a connection by calling the Open() method of the
SqlConnection instance, conn. Any operations on a connection that was
not yet opened will generate an exception. So, you must open the
connection before using it.
Before using a connection, you must let
the ADO.NET code know which connection it needs. In Listing 1, we set
the second parameter to the SqlCommand object with the SqlConnection
object, conn. Any operations performed with the SqlCommand will use
that connection.
The code that uses the connection is a SqlCommand
object, which performs a query on the Customers table. The result set
is returned as a SqlDataReader and the while loop reads the first
column from each row of the result set, which is the CustomerID
column. We'll discuss the SqlCommand and SqlDataReader objects in
later lessons. For right now, it is important for you to understand
that these objects are using the SqlConnection object so they know
what database to interact with.
When you are done using the
connection object, you must close it. Failure to do so could have
serious consequences in the performance and scalability of your
application. There are a couple points to be made about how we closed
the connection in Listing 1: the Close() method is called in a finally
block and we ensure that the connection is not null before closing
it.
Notice that we wrapped the ADO.NET code in a try/finally block.
As described in Lesson 15: Introduction to Exception Handling of the
C# Tutorial, finally blocks help guarantee that a certain piece of
code will be executed, regardless of whether or not an exception is
generated. Since connections are scarce system resources, you will
want to make sure they are closed in finally blocks.
Another
precaution you should take when closing connections is to make sure
the connection object is not null. If something goes wrong when
instantiating the connection, it will be null and you want to make
sure you don't try to close an invalid connection, which would
generate an exception.
This example showed how to use a
SqlConnection object with a SqlDataReader, which required explicitly
closing the connection. However, when using a disconnected data model,
you don't have to open and close the connection yourself. We'll see
how this works in a future lesson when we look at the SqlDataAdapter
object.
Summary
SqlConnection objects let other ADO.NET code
know what data base to connect to and how to make the connection. They
are instantiated by passing a connection string with a set of
key/value pairs that define the connection. The steps you use to
manage the lifetime of a connection are create, open, pass, use, and
close. Be sure to close your connection properly when you are done
with it to ensure you don't have a connection resource leak.
Lesson
03: The SqlCommand Object
This lesson describes the SqlCommand
object and how you use it to interact with a data base. Here are the
objectives of this lesson:
· Know what a command object is.
·
Learn how to use the ExecuteReader method to query data.
· Learn
how to use the ExecuteNonQuery method to insert and delete data.
·
Learn how to use the ExecuteScalar method to return a single
value.
Introduction
A SqlCommand object allows you to specify
what type of interaction you want to perform with a data base. For
example, you can do select, insert, modify, and delete commands on
rows of data in a data base table. The SqlCommand object can be used
to support disconnected data management scenarios, but in this lesson
we will only use the SqlCommand object alone. A later lesson on the
SqlDataAdapter will explain how to implement an application that uses
disconnected data. This lesson will also show you how to retrieve a
single value from a data base, such as the number of records in a
table.
Creating a SqlCommand Object
Similar to other C# objects,
you instantiate a SqlCommand object via the new instance declaration,
as follows:
SqlCommand cmd = new SqlCommand("select CategoryName
from Categories", conn);
The line above is typical for
instantiating a SqlCommand object. It takes a string parameter that
holds the command you want to execute and a reference to a
SqlConnection object. SqlCommand has a few overloads, which you will
see in the examples of this tutorial.
Querying Data
When using a
SQL select command, you retrieve a data set for viewing. To accomplish
this with a SqlCommand object, you would use the ExecuteReader method,
which returns a SqlDataReader object. We'll discuss the SqlDataReader
in a future lesson. The example below shows how to use the SqlCommand
object to obtain a SqlDataReader object:
// 1. Instantiate a new
command with a query and connection
SqlCommand cmd = new
SqlCommand("select CategoryName from Categories", conn);
// 2.
Call Execute reader to get query results
SqlDataReader rdr =
cmd.ExecuteReader();
In the example above, we instantiate a
SqlCommand object, passing the command string and connection object to
the constructor. Then we obtain a SqlDataReader object by calling the
ExecuteReader method of the SqlCommand object, cmd.
This code is
part of the ReadData method of Listing 1 in the Putting it All
Together section later in this lesson.
Inserting Data
To insert
data into a data base, use the ExecuteNonQuery method of the
SqlCommand object. The following code shows how to insert data into a
data base table:
// prepare command string
string insertString =
@"
insert into Categories
(CategoryName, Description)
values
('Miscellaneous', 'Whatever doesn''t fit elsewhere')";
// 1.
Instantiate a new command with a query and connection
SqlCommand
cmd = new SqlCommand(insertString, conn);
// 2. Call
ExecuteNonQuery to send command
cmd.ExecuteNonQuery();
The
SqlCommand instantiation is just a little different from what you've
seen before, but it is basically the same. Instead of a literal string
as the first parameter of the SqlCommand constructor, we are using a
variable, insertString. The insertString variable is declared just
above the SqlCommand declaration.
Notice the two apostrophes ('')
in the insertString text for the word "doesn''t". This is how you
escape the apostrophe to get the string to populate column properly.
Another observation to make about the insert command is that we
explicitly specified the columns CategoryName and Description. The
Categories table has a primary key field named CategoryID. We left
this out of the list because SQL Server will add this field itself.
trying to add a value to a primary key field, such as CategoryID, will
generate an exception.
To execute this command, we simply call the
ExecuteNonQuery method on the SqlCommand instance, cmd.
This code
is part of the Insertdata method of Listing 1 in the Putting it All
Together section later in this lesson.
Updating Data
The
ExecuteNonQuery method is also used for updating data. The following
code shows how to update data:
// prepare command string
string
updateString = @"
update Categories
set CategoryName =
'Other'
where CategoryName = 'Miscellaneous'";
// 1.
Instantiate a new command with command text only
SqlCommand cmd =
new SqlCommand(updateString);
// 2. Set the Connection
property
cmd.Connection = conn;
// 3. Call ExecuteNonQuery
to send command
cmd.ExecuteNonQuery();
Again, we put the SQL
command into a string variable, but this time we used a different
SqlCommand constructor that takes only the command. In step 2, we
assign the SqlConnection object, conn, to the Connection property of
the SqlCommand object, cmd.
This could have been done with the
same constructor used for the insert command, with two parameters. It
demonstrates that you can change the connection object assigned to a
command at any time.
The ExecuteNonQuery method performs the update
command.
This code is part of the UpdateData method of Listing 1 in
the Putting it All Together section later in this lesson.
Deleting
Data
You can also delete data using the ExecuteNonQuery method. The
following example shows how to delete a record from a data base with
the ExecuteNonQuery method:
// prepare command string
string
deleteString = @"
delete from Categories
where CategoryName =
'Other'";
// 1. Instantiate a new command
SqlCommand cmd =
new SqlCommand();
// 2. Set the CommandText
property
cmd.CommandText = deleteString;
// 3. Set the
Connection property
cmd.Connection = conn;
// 4. Call
ExecuteNonQuery to send command
cmd.ExecuteNonQuery();
This
example uses the SqlCommand constructor with no parameters. Instead,
it explicity sets the CommandText and Connection properties of the
SqlCommand object, cmd.
We could have also used either of the two
previous SqlCommand constructor overloads, used for the insert or
update command, with the same result. This demonstrates that you can
change both the command text and the connection object at any time.
The ExecuteNonQuery method call sends the command to the data
base.
This code is part of the DeleteData method of Listing 1 in
the Putting it All Together section later in this lesson.
Getting
Single values
Sometimes all you need from a data base is a single
value, which could be a count, sum, average, or other aggregated value
from a data set. Performing an ExecuteReader and calculating the
result in your code is not the most efficient way to do this. The best
choice is to let the data base perform the work and return just the
single value you need. The following example shows how to do this with
the ExecuteScalar method:
// 1. Instantiate a new
command
SqlCommand cmd = new SqlCommand("select count(*) from
Categories", conn);
// 2. Call ExecuteNonQuery to send
command
int count = (int)cmd.ExecuteScalar();
The query in the
SqlCommand constructor obtains the count of all records from the
Categories table. This query will only return a single value. The
ExecuteScalar method in step 2 returns this value. Since the return
type of ExecuteScalar is type object, we use a cast operator to
convert the value to int.
This code is part of the
GetNumberOfRecords method of Listing 1 in the Putting it All Together
section later in this lesson.
Putting it All Together
For
simplicity, we showed snippets of code in previous sections to
demonstrate the applicable techniques . It is also useful to have an
entire code listing to see how this code is used in a working program.
Listing 1 shows all of the code used in this example, along with a
driver in the Main method to produce formatted output.
Listing 1.
SqlConnection Demo
using System;
using System.Data;
using
System.Data.SqlClient;
///
/// Demonstrates how to work
with SqlCommand objects
///
class
SqlCommandDemo
{
SqlConnection conn;
public
SqlCommandDemo()
{
// Instantiate the connection
conn = new
SqlConnection(
"Data Source=(local);Initial
Catalog=Northwind;Integrated Security=SSPI");
}
// call
methods that demo SqlCommand capabilities
static void
Main()
{
SqlCommandDemo scd = new
SqlCommandDemo();
Console.WriteLine();
Console.WriteLine("Ca
tegories Before
Insert");
Console.WriteLine("------------------------");
//
use ExecuteReader method
scd.ReadData();
// use
ExecuteNonQuery method for
Insert
scd.Insertdata();
Console.WriteLine();
Console.WriteLi
ne("Categories After
Insert");
Console.WriteLine("------------------------------");
<
BR>scd.ReadData();
// use ExecuteNonQuery method for
Update
scd.UpdateData();
Console.WriteLine();
Console.Wri
teLine("Categories After
Update");
Console.WriteLine("------------------------------");
<
BR>scd.ReadData();
// use ExecuteNonQuery method for
Delete
scd.DeleteData();
Console.WriteLine();
Console.Wri
teLine("Categories After
Delete");
Console.WriteLine("------------------------------");
<
BR>scd.ReadData();
// use ExecuteScalar method
int
numberOfRecords =
scd.GetNumberOfRecords();
Console.WriteLine();
Console.Write
Line("Number of Records: {0}", numberOfRecords);
}
///
/// use ExecuteReader method
///
public void
ReadData()
{
SqlDataReader rdr = null;
try
{
//
Open the connection
conn.Open();
// 1. Instantiate a new
command with a query and connection
SqlCommand cmd = new
SqlCommand("select CategoryName from Categories", conn);
// 2.
Call Execute reader to get query results
rdr =
cmd.ExecuteReader();
// print the CategoryName of each
record
while
(rdr.Read())
{
Console.WriteLine(rdr[0]);
}
}
finally{
// close the reader
if (rdr !=
null)
{
rdr.Close();
}
// Close the connection
if
(conn != null)
{
conn.Close();
}
}
}
///
///
use ExecuteNonQuery method for Insert
///
public void
Insertdata()
{
try
{
// Open the
connection
conn.Open();
// prepare command string
string
insertString = @"
insert into Categories
(CategoryName,
Description)
values ('Miscellaneous', 'Whatever doesn''t fit
elsewhere')";
// 1. Instantiate a new command with a query and
connection
SqlCommand cmd = new SqlCommand(insertString,
conn);
// 2. Call ExecuteNonQuery to send
command
cmd.ExecuteNonQuery();
}
finally
{
// Close the
connection
if (conn !=
null)
{
conn.Close();
}
}
}
///
/// use
ExecuteNonQuery method for Update
///
public void
UpdateData()
{
try
{
// Open the
connection
conn.Open();
// prepare command string
string
updateString = @"
update Categories
set CategoryName =
'Other'
where CategoryName = 'Miscellaneous'";
// 1.
Instantiate a new command with command text only
SqlCommand cmd =
new SqlCommand(updateString);
// 2. Set the Connection
property
cmd.Connection = conn;
// 3. Call ExecuteNonQuery
to send command
cmd.ExecuteNonQuery();
}
finally
{
//
Close the connection
if (conn !=
null)
{
conn.Close();
}
}
}
///
/// use
ExecuteNonQuery method for Delete
///
public void
DeleteData()
{
try
{
// Open the
connection
conn.Open();
// prepare command string
string
deleteString = @"
delete from Categories
where CategoryName =
'Other'";
// 1. Instantiate a new command
SqlCommand cmd =
new SqlCommand();
// 2. Set the CommandText
property
cmd.CommandText = deleteString;
// 3. Set the
Connection property
cmd.Connection = conn;
// 4. Call
ExecuteNonQuery to send
command
cmd.ExecuteNonQuery();
}
finally
{
// Close the
connection
if (conn !=
null)
{
conn.Close();
}
}
}
///
/// use
ExecuteScalar method
///
/// number of records
public int
GetNumberOfRecords()
{
int count = -1;
try
{
//
Open the connection
conn.Open();
// 1. Instantiate a new
command
SqlCommand cmd = new SqlCommand("select count(*) from
Categories", conn);
// 2. Call ExecuteNonQuery to send
command
count =
(int)cmd.ExecuteScalar();
}
finally
{
// Close the
connection
if (conn !=
null)
{
conn.Close();
}
}
return count;
}
}
In
Listing 1, the SqlConnection object is instantiated in the
SqlCommandDemo structure. This is okay because the object itself will
be cleaned up when the CLR garbage collector executes. What is
important is that we close the connection when we are done using it.
This program opens the connection in a try block and closes it in a
finally block in each method.
The ReadData method displays the
contents of the CategoryName column of the Categories table. We use it
several times in the Main method to show the current status of the
Categories table, which changes after each of the insert, update, and
delete commands. Because of this, it is convenient to reuse to show
you the effects after each method call.
Summary
A SqlCommand
object allows you to query and send commands to a data base. It has
methods that are specialized for different commands. The ExecuteReader
method returns a SqlDataReader object for viewing the results of a
select query. For insert, update, and delete SQL commands, you use the
ExecuteNonQuery method. If you only need a single aggregate value from
a query, the ExecuteScalar is the best choice.
Lesson 04:
Reading Data with the SqlDataReader
This lesson explains how to
read data with a SqlDataReader object. Here are the objectives of this
lesson:
· Learn what a SqlDataReader is used for.
· Know how
to read data using a SqlDataReader.
· Understand the need to close
a SqlDataReader.
Introduction
A SqlDataReader is a type that is
good for reading data in the most efficient manner possible. You can
*not* use it for writing data. SqlDataReaders are often described as
fast-forward firehose-like streams of data.
You can read from
SqlDataReader objects in a forward-only sequential manner. Once you've
read some data, you must save it because you will not be able to go
back and read it again.
The forward only design of the
SqlDataReader is what enables it to be fast. It doesn't have overhead
associated with traversing the data or writing it back to the data
source. Therefore, if your only requirement for a group of data is for
reading one time and you want the fastest method possible, the
SqlDataReader is the best choice. Also, if the amount of data you need
to read is larger than what you would prefer to hold in memory beyond
a single call, then the streaming behavior of the SqlDataReader would
be a good choice.
Note: Observe that I used the term "one time" in
the previous paragraph when discussing the reasons why you would use a
SqlDataReader. As with anything, there are exceptions. In many cases,
it is more efficient to use a cached DataSet. While caching is outside
the scope of this tutorial, we will discuss using DataSet objects in
the next lesson.
Creating a SqlDataReader Object
Getting an
instance of a SqlDataReader is a little different than the way you
instantiate other ADO.NET objects. You must call ExecuteReader on a
command object, like this:
SqlDataReader rdr =
cmd.ExecuteReader();
The ExecuteReader method of the SqlCommand
object, cmd , returns a SqlDataReader instance. Creating a
SqlDataReader with the new operator doesn't do anything for you. As
you learned in previous lessons, the SqlCommand object references the
connection and the SQL statement necessary for the SqlDataReader to
obtain data.
Reading Data
previous lessons contained code that
used a SqlDataReader, but the discussion was delayed so we could focus
on the specific subject of that particular lesson. This lesson builds
from what you've seen and explains how to use the SqlDataReader.
As
explained earlier, the SqlDataReader returns data via a sequential
stream. To read this data, you must pull data from a table row-by-row.
Once a row has been read, the previous row is no longer available. To
read that row again, you would have to create a new instance of the
SqlDataReader and read through the data stream again.
The typical
method of reading from the data stream returned by the SqlDataReader
is to iterate through each row with a while loop. The following code
shows how to accomplish this:
while (rdr.Read())
{
// get the
results of each column
string contact =
(string)rdr["ContactName"];
string company =
(string)rdr["CompanyName"];
string city =
(string)rdr["City"];
// print out the
results
Console.Write("{0,-25}",
contact);
Console.Write("{0,-20}",
city);
Console.Write("{0,-25}",
company);
Console.WriteLine();
}
Notice the call to Read on
the SqlDataReader, rdr, in the while loop condition in the code above.
The return value of Read is type bool and returns true as long as
there are more records to read. After the last record in the data
stream has been read, Read returns false.
In previous lessons, we
extracted the first column from the row by using the SqlDataReader
indexer, i.e. rdr[0]. You can extract each column of the row with a
numeric indexer like this, but it isn't very readable. The example
above uses a string indexer, where the string is the column name from
the SQL query (the table column name if you used an asterisk, *.
String indexers are much more readable, making the code easier to
maintain.
Regardless of the type of the indexer parameter, a
SqlDataReader indexer will return type object. This is why the example
above casts results to a string. Once the values are extracted, you
can do whatever you want with them, such as printing them to output
with Console type methods.
Finishing Up
Always remember to close
your SqlDataReader, just like you need to close the SqlConnection.
Wrap the data access code in a try block and put the close operation
in the finally block, like this:
try
{
// data access
code
}
finally
{
// 3. close the reader
if (rdr !=
null)
{
rdr.Close();
}
// close the connection
too
}
The code above checks the SqlDataReader to make sure it
isn't null. After the code knows that a good instance of the
SqlDataReader exists, it can close it. Listing 1 shows the code for
the previous sections in its entirety.
Listing 1: Using the
SqlDataReader
using System;
using System.Data;
using
System.Data.SqlClient;
namespace Lesson04
{
class
ReaderDemo
{
static void Main()
{
ReaderDemo rd = new
ReaderDemo();
rd.SimpleRead();
}
public void
SimpleRead()
{
// declare the SqlDataReader, which is used
in
// both the try block and the finally block
SqlDataReader rdr
= null;
// create a connection object
SqlConnection conn =
new SqlConnection(
"Data Source=(local);Initial
Catalog=Northwind;Integrated Security=SSPI");
// create a
command object
SqlCommand cmd = new SqlCommand(
"select * from
Customers", conn);
try
{
// open the
connection
conn.Open();
// 1. get an instance of the
SqlDataReader
rdr = cmd.ExecuteReader();
// print a set of
column headers
Console.WriteLine(
"Contact Name City Company
Name");
Console.WriteLine(
"------------ ------------
------------");
// 2. print necessary columns of each
record
while (rdr.Read())
{
// get the results of each
column
string contact = (string)rdr["ContactName"];
string
company = (string)rdr["CompanyName"];
string city =
(string)rdr["City"];
// print out the
results
Console.Write("{0,-25}",
contact);
Console.Write("{0,-20}",
city);
Console.Write("{0,-25}",
company);
Console.WriteLine();
}
}
finally
{
// 3.
close the reader
if (rdr !=
null)
{
rdr.Close();
}
// close the connection
if
(conn != null)
{
conn.Close();
}
}
}
}
}
Summary
SqlDataReader objects allow you to read
data in a fast forward-only manner. You obtain data by reading each
row from the data stream. Call the Close method of the SqlDataReader
to ensure there are not any resource leaks.
Lesson 05: Working with
Disconnected Data - The DataSet and SqlDataAdapter
This lesson
explains how to work with disconnected data, using the DataSet and
SqlDataAdapter objects. Here are the objectives of this lesson:
·
Understand the need for disconnected data.
· Obtain a basic
understanding of what a DataSet is for.
· Learn to use a
SqlDataAdapter to retrieve and update data.
Introduction
In
Lesson 3, we discussed a fully connected mode of operation for
interacting with a data source by using the SqlCommand object. In
Lesson 4, we learned about how to read data quickly an let go of the
connection with the SqlDataReader. This Lesson shows how to accomplish
something in-between SqlConnection and SqlDataReader interaction by
using the DataSet and SqlDataAdapter objects.
A DataSet is an
in-memory data store that can hold numerous tables. DataSets only hold
data and do not interact with a data source. It is the SqlDataAdapter
that manages connections with the data source and gives us
disconnected behavior. The SqlDataAdapter opens a connection only when
required and closes it as soon as it has performed its task. For
example, the SqlDataAdapter performs the following tasks when filling
a DataSet with data:
1. Open connection
2. Retrieve data into
DataSet
3. Close connection
and performs the following actions
when updating data source with DataSet changes:
1. Open
connection
2. Write changes from DataSet to data source
3. Close
connection
In between the Fill and Update operations, data source
connections are closed and you are free to read and write data with
the DataSet as you need. These are the mechanics of working with
disconnected data. Because the applications holds on to connections
only when necessary, the application becomes more scalable.
A
couple scenarios illustrate why you would want to work with
disconnected data: people working without network connectivity and
making Web sites more scalable. Consider sales people who need
customer data as they travel. At the beginning of the day, they'll
need to sync up with the main data base to have the latest information
available. During the day, they'll make modifications to existing
customer data, add new customers, and input new orders. This is okay
because they have a given region or customer base where other people
won't be changing the same records. At the end of the day, the sales
person will connect to the network and update changes for overnight
processing.
Another scenario is making a Web site more scalable.
With a SqlDataReader, you have to go back to the data base for records
every time you show a page. This requires a new connection for each
page load, which will hurt scalability as the number of users
increase. One way to relieve this is to use a DataSet that is updated
one time and stored in cache. Ev