OleDbConnection SqlConnection ActiveX Data Objectsstudents.cypresscollege.edu/cis223/lc14.pdf ·...
Transcript of OleDbConnection SqlConnection ActiveX Data Objectsstudents.cypresscollege.edu/cis223/lc14.pdf ·...
Visual C++ Programming – Penn Wu, PhD 367
Lecture #14 Connecting to Database
Introduction The term OLE DB refers to a set of Component Object Model (COM) interfaces that provide
applications with uniform access to data stored in diverse information sources, such as a file or e-
mail system, a database, or a resource on the Internet. According to the OLE DB model, the
application request desired data from the source, the source returns a copy of the desired data to
the application, the machine that runs the application held the delivered data in computer memory,
the application then go to the memory to locate, examine, modify, delete, insert, or update the
data. Finally, any changes made in the memory are delivered back to the data source by the
application. The following figure illustrates the flow of processing. A Data Source represents the
data that is available to an application.
To bring data into your application (and send changes back to the data source), some kind of two-
way communication needs to be established. This two-way communication is typically handled by
a connection object (for example, an OleDbConnection or a SqlConnection) that is configured
with a connection string, the information it needs to connect to the data source. Data retrieval is
done through the use of SQL (Structured Query Language) statements. SQL is an international
standard for database manipulation.
The .NET Framework also uses Microsoft’s ActiveX Data Objects (ADO) to enable the client
applications to access and manipulate data from a variety of sources through an OLE DB provider.
The .NET Framework’s DataSet object is central to supporting disconnected, distributed data
scenarios with ADO.NET. The lecture will discuss three ways to use the ADO.NET to implement
data.
• Populate the DataSet with tables of data from an existing relational data source using a
DataAdapter.
• Programmatically create a DataTable within a DataSet and populate the tables with data.
• Load and persist the DataSet contents using XML.
Building an
open
connection to a
data source
An OleDbConnection object represents a unique connection to a data source. With a client/server
database system, it is equivalent to a network connection to the server. Depending on the
functionality supported by the native OLE DB provider, some methods or properties of an
OleDbConnection object may not be available. The following creates an OleDbConnection
object, conn, using the OleDbConnection() constructor. When you create an instance of
OleDbConnection, all properties are set to their initial values. For a list of these values.
OleDbConnection^ conn = gcnew OleDbConnection();
The ConnectionString property defines the source database name, and other parameters needed
to establish the initial connection. One key parameter is the “Provider = value” clause which
is required to specify the driver type. Another required parameter is the “Data Source” property
which specifies the location of the database file. Interestingly, if the “Data Source” property is not
specified in the connection string, the provider will try to connect to the local server if one is
available. Keywords for setting the parameters are not case sensitive.
In the following, it sets the string used to open a MS Access database file named “emp.mdb”,
which is saved to the “C:\cis223” directory. By the way, Microsoft’s ODBC uses Jet.OLEDB.4.0
Application
Memory Data
Source
begin
end
Visual C++ Programming – Penn Wu, PhD 368
driver as default driver to connect Microsoft Access database file. Notice that \\ is the sequence
escape.
conn->ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=C:\\cis223\\emp.mdb";
If the .mdb file resides in the same directory as the application, simply the “Date Source” to:
conn->ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=emp.mdb";
The ConnectionString is designed to match OLE DB connection string format as closely as
possible. You can use the ConnectionString property to connect to a variety of data sources. The
following examples illustrate three kinds of connection strings for three different kinds of
database engines. When specifying a local instance, always use (local).
• For Oracle server: "Provider=MSDAORA;Data Source=ORACLE8i7;Persist Security Info=False;Integrated Security=Yes";
• For Microsoft Access database: "Provider=Microsoft.Jet.OLEDB.4.0;Data Source= c:\\myData.mdb";
• For MS SQL server: "Provider=SQLOLEDB;Data Source=(local);Integrated Security=SSPI";
The following code illustrates how to build a connection to a Microsoft Access database file in the
local machine, and then return the status of the connection. The OleDbConnection::State property
returns the current state of the connection. The default is Closed. The OleDbConnection::Open()
method opens a database connection with the property settings specified by the ConnectionString.
#using <System.dll>
#using <System.Windows.Forms.dll>
#using <System.Data.dll>
using namespace System;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Data::OleDb;
int main()
{
OleDbConnection^ conn = gcnew OleDbConnection();
conn->ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=emp.mdb";
conn->Open();
MessageBox::Show(Convert::ToString(conn->State));
}
If the “emp.mdb” file is available and the connection is opened, the output looks:
Running the
query
Once the connection is made and maintained, you can use the OleDbCommand class to set an
SQL statement for execution to retrieve data from the data source. The syntax is:
Visual C++ Programming – Penn Wu, PhD 369
OleDbCommand(queryString);
For example,
OleDbCommand^ cmd = gcnew OleDbCommand("Select * from
Departments");
The following is another form which initializes a new instance of the OleDbCommand class with
the text of the query and an OleDbConnection.
OleDbCommand(queryString, oleDbConnection);
For example,
OleDbCommand^ cmd = gcnew OleDbCommand("Select * from
Departments", conn);
The returned query results needs a handle to implement them. The OleDbDataReader class
provides a way of reading a forward-only stream of data rows from a data source. The following
creates an OleDbDataReader object named “rd” and use it as record set. You must call the
ExecuteReader() method of the OleDbCommand object, instead of directly using a constructor.
OleDbDataReader^ rd = cmd->ExecuteReader();
A record set is an array of data retrieved through a query; therefore, the “rd” object created above
is an array. All its elements are represented by the rd[i] format. The Departments table is
available in the “emp.mdb” file. It has the following records. The first record, not the name of
columns, can be expressed as a String^ array with three elements: “S01”, “Sales”, and “Room
101”. In this case, they are represented by rd[0], rd[1], and rd[2] respectively.
DEPTID Department Location
S01 Sales Room 101
W01 Warehouse Room 102
A01 Administration Room 103
When a table contains more than one records, the query will retrieve them on a one-at-time basis.
The Read() method advances the OleDbDataReader to the next record. The following use a while
loop to reads through the data, writing it out to a string literal. The GetName() method returns the
name of the specified column (also known as “field”).
String^ str = "";
str += rd->GetName(0) + "\t" + rd->GetName(1) + "\t" + rd-
>GetName(2) + "\n";
while (rd->Read())
{
str += rd[0] + "\t" + rd[1] + "\t" + rd[2] + "\n";
}
The GetString() method can return the value of the specified column as a string. The following
produces the same result as the above.
while (rd->Read())
{
str += rd->GetString(0) + "\t" + rd->GetString(1) + "\t" + rd-
>GetString(2) + "\n";
}
Visual C++ Programming – Penn Wu, PhD 370
The following is a complete sample code that illustrates how you manually develop the code to
retrieve data from a table in a Microsoft Access database file.
#using <System.dll>
#using <System.Windows.Forms.dll>
#using <System.Data.dll>
using namespace System;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Data::OleDb;
int main()
{
OleDbConnection^ conn = gcnew OleDbConnection();
conn->ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=emp.mdb";
conn->Open();
OleDbCommand^ cmd = gcnew OleDbCommand("Select * from
Departments", conn);
OleDbDataReader^ rd = cmd->ExecuteReader();
String^ str = "";
str += rd->GetName(0) + "\t" + rd->GetName(1) + "\t" + rd-
>GetName(2) + "\n";
while (rd->Read())
{
str += rd[0] + "\t" + rd[1] + "\t" + rd[2] + "\n";
}
conn->Close();
MessageBox::Show(str);
}
The output looks:
It is always a good practice to use the Close() method to close the connection to the data source
upon finishing the access to the demanded data.
conn->Close();
Ironically, all of Microsoft’s 64-bit OS products do not support the Microsoft.Jet.OLEDB.4.0
driver. There is no 64-bit version Jet.OLEDB driver. If your application is run as 64-bit program,
Visual C++ Programming – Penn Wu, PhD 371
you may encounter the following error. If the application is built as an x86 application, it will
work proper. See http://support.microsoft.com/kb/957570 for details.
"Microsoft.Jet.OLEDB.4.0" has not been registered.
Without providing suggestions, Microsoft states “in a 64-bit Windows environment, you can run
an application in the 32-bit mode. Therefore, the application can use the 32-bit version of the
Microsoft OLE DB Provider for Jet or the 32-bit version of the Jet ODBC driver.”
You also have to use the right compiler. There are three of them:
• vc\bin\cl.exe is the 32-bit compiler
• vc\bin\x86_amd64\cl.exe is a 32-bit compiler that generates 64-bit code
• vc\bin\amd64\cl.exe is a 64-bit compiler that generates 64-bit code
Another solution is to change the provider to
"Provider=Microsoft.ACE.OLEDB.12.0;"
For example,
"Provider=Microsoft.ACE.OLEDB.12.0; Data Source=c:\myData.mdb";
Apply the concept of exception handling to this case is another possible solution. The following
demonstrates how you can try the Jet.OLEDB driver and use the ACE.OLEDB driver if error
occurs.
try
{
// use Jet.OLEDB if available
conn->ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=emp.mdb";
}
catch (Exception^ e)
{
MessageBox::Show(e->ToString());
// use ACE.OLEDB if Jet.OLEDB is not available
conn->ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data
Source=emp.mdb";
}
Using adapter
to retrieve data
In addition to the OleDbCommand class, the OleDbDataAdapter class also provides a set of
data commands and a database connection that are used to fill the DataSet and update the data
source.
The OleDbDataAdapter serves as a bridge between a DataSet and data source for retrieving and
saving data. The OleDbDataAdapter provides this bridge by using Fill to load data from the data
source into the DataSet, and using Update to send changes made in the DataSet back to the data
source.
The OleDbDataAdapter() constructor initializes a new instance of the OleDbDataAdapter class.
The following creates an OleDbDataAdapter object named da using the OleDbDataAdapter()
constructor, which initializes a new instance of the OleDbDataAdapter class with a “Select” SQL
statement.
OleDbConnection^ conn = gcnew OleDbConnection();
conn->ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=emp.mdb";
Visual C++ Programming – Penn Wu, PhD 372
conn->Open();
String^ sql = "Select * from Departments";
OleDbDataAdapter^ da = gcnew OleDbDataAdapter(sql, conn);
You can also place the SQL statement in the OleDbDataAdapter() constructor.
OleDbDataAdapter^ da = gcnew OleDbDataAdapter("Select * from
Departments", conn);
The Departments table is available in the “emp.mdb” file. It has the following records.
DEPTID Department Location
S01 Sales Room 101
W01 Warehouse Room 102
A01 Administration Room 103
The DataSet class of the ADO.NET architecture provides member to create an in-memory cache
of data retrieved from a data source. All the data store in a table of a database file (e.g. the data in
the “Departments” table) must be retrieved and temporarily stored in the computer memory
represented by a DataSet object. A DataSet object then use methods and properties provided by
the DataSet class to read and write data. The following creates DataSet object named ds. The
DataSet() constructor initializes a new instance of the DataSet class. The identifier of this instance
is “ds”.
DataSet^ ds = gcnew DataSet();
You can optionally specify a name argument such as “dept” in the following example.
DataSet^ ds = gcnew DataSet("dept");
The Fill() method of the OleDbDataAdapter can load data from the data source into the DataSet
object as illustrated below:
da->Fill(ds, "Departments");
The following code segment illustrates how to connect to an existing Microsoft Access database
named “emp.mdb”, perform a SQL query, create an instance of OleDbDataAdapter named “da”,
create an instance of DataSet named “ds”, and then use the Fill() method to load the data provided
by “ds”.
OleDbConnection^ conn = gcnew OleDbConnection();
conn->ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=emp.mdb";
conn->Open();
String^ sql = "Select * from Departments";
OleDbDataAdapter^ da = gcnew OleDbDataAdapter(sql, conn);
DataSet^ ds = gcnew DataSet();
da->Fill(ds, "Departments");
If the OleDbConnection goes out of scope, it is not closed. Therefore, you must explicitly close
the connection by calling Close or Dispose, or by using the OleDbConnection object within a
Using statement.
Visual C++ Programming – Penn Wu, PhD 373
conn->Close();
The following is the complete sample code.
#using <System.dll>
#using <System.Drawing.dll>
#using <System.Windows.Forms.dll>
#using <System.Data.dll>
using namespace System;
using namespace System::Windows::Forms;
using namespace System::Drawing;
using namespace System::Data;
using namespace System::Data::OleDb;
int main()
{
Form^ form1 = gcnew Form;
OleDbConnection^ conn = gcnew OleDbConnection();
conn->ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=emp.mdb";
conn->Open();
String^ sql = "Select * from Departments";
OleDbDataAdapter^ da = gcnew OleDbDataAdapter(sql, conn);
DataSet^ ds = gcnew DataSet();
da->Fill(ds, "Departments");
DataGrid^ datagrid1 = gcnew DataGrid();
datagrid1->DataSource = ds->Tables["Departments"]->DefaultView;
datagrid1->Location = Point(10, 10);
datagrid1->Size = Drawing::Size(270, 250);
conn->Close();
form1->Controls->Add(datagrid1);
Application::Run(form1);
}
A sample output looks:
Displaying data
Using a
DataGridView,
DataGrid,
DataView, and
DataTable
After retrieving the data, the application needs to display them on the form for users to view or
modify. A DataSet can be bound to a variety of controls in a user interface, such as
DataGridView and DataGrid, which displays ADO.NET data in a scrollable grid. The above
code illustrates how to use the DataGrid. It is necessary to note that Visual Studio 2010 begins
using the DataGridView control to replace the DataGrid control, although the DataGrid control
is retained for both backward compatibility and future use.
Visual C++ Programming – Penn Wu, PhD 374
The DataGrid() constructor initializes a new instance of the DataGrid class.
DataGrid^ datagrid1 = gcnew DataGrid();
To populate a newly created DataGrid control, set the DataSource property to a valid source. The
following is an example that explains how to use a MS Access table as data source. It uses the
Tables property of the DataSet class to get the array of tables contained in the DataSet, because a
DataSet instance may contains more than one tables. The Tables property supports the DataTable
class which represents one table of in-memory data; therefore it works with the DataView type of
objects. The following also uses the DefaultView property to specify that the DataView is a
generic Excel-like 2-dimensional table.
datagrid1->DataSource = ds->Tables["Departments"]->DefaultView;
Another way to display a table in the DataGrid is to use the SetDataBinding() method to set the
DataSource property to a valid data source. For example, the following bold-faced statement can
replace the above statement and still produce the same result.
DataGrid^ datagrid1 = gcnew DataGrid();
datagrid1->SetDataBinding(ds, "Departments");
The following specifies how to place the DataGrid in a Windows form.
datagrid1->Location = Point(10, 10);
datagrid1->Size = Drawing::Size(270, 250);
.......
Controls->Add(datagrid1);
Similar to the DataGrid, the DataGridView control works with the Tables property as illustrated
below.
DataSet^ ds = gcnew DataSet();
da->Fill(ds, "Departments");
DataGridView^ dataGridView1 = gcnew DataGridView;
dataGridView1->DataSource = ds->Tables["Departments"]-
>DefaultView;
dataGridView1->Location = Point(10, 10);
dataGridView1->AutoSize = true;
form1->Controls->Add(dataGridView1);
On the other hand, the DataGridView class support the BindingSource class which can bind the
data source to a customizable table for displaying data. The following demonstrates how to use the
BindingSource() contractor to bind the data source.
DataGridView^ dataGridView1 = gcnew DataGridView;
dataGridView1->DataSource = gcnew BindingSource(ds,
"Departments");
The following is a complete code of the DataGridView version.
#using <System.dll>
#using <System.Drawing.dll>
#using <System.Windows.Forms.dll>
#using <System.Data.dll>
using namespace System;
Visual C++ Programming – Penn Wu, PhD 375
using namespace System::Windows::Forms;
using namespace System::Drawing;
using namespace System::Data;
using namespace System::Data::OleDb;
int main()
{
Form^ form1 = gcnew Form;
OleDbConnection^ conn = gcnew OleDbConnection();
conn->ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=emp.mdb";
conn->Open();
String^ sql = "Select * from Departments";
OleDbDataAdapter^ da = gcnew OleDbDataAdapter(sql, conn);
DataSet^ ds = gcnew DataSet();
da->Fill(ds, "Departments");
DataGridView^ dataGridView1 = gcnew DataGridView;
dataGridView1->DataSource = gcnew BindingSource(ds,
"Departments");
dataGridView1->Location = Point(10, 10);
dataGridView1->AutoSize = true;
form1->Controls->Add(dataGridView1);
conn->Close();
form1->Size = Size(400, 200);
Application::Run(form1);
}
The DataGridView class allows customization of cells, rows, columns, and borders through the
use of properties such as DefaultCellStyle, ColumnHeadersDefaultCellStyle, CellBorderStyle,
and GridColor. For example,
// A three-dimensional sunken border.
dataGridView1->CellBorderStyle =
DataGridViewCellBorderStyle::Sunken;
// Set the DataGridView control's border.
dataGridView1->BorderStyle = BorderStyle::Fixed3D;
// Put the cells in edit mode when user enters them.
dataGridView1->EditMode = DataGridViewEditMode::EditOnEnter;
The DataTable class provides another way to bind the data. However, it still relies on
DataGridView to display date in a tabular format. The following example demonstrates how to
create an instance of DataTable, load the data retrieved by OleDbDataAdapter to it through the
Fill() method, and then use it as data source to display data in a DataGridView.
String^ sql = "Select * from Departments";
OleDbDataAdapter^ da = gcnew OleDbDataAdapter(sql, conn);
DataTable^ dt1 = gcnew DataTable();
da->Fill(dt1);
Visual C++ Programming – Penn Wu, PhD 376
DataGridView^ dataGridView1 = gcnew DataGridView;
dataGridView1->DataSource = dt1;
dataGridView1->Location = Point(10, 10);
dataGridView1->AutoSize = true;
form1->Controls->Add(dataGridView1);
Updating the
data in a
database file
You can reuse the same OleDbDataAdapter object with different SQL query on a single
OleDbConnection. For example,
String^ sql = "Select * from Departments";
OleDbDataAdapter^ da = gcnew OleDbDataAdapter(sql, conn);
DataSet^ ds = gcnew DataSet();
da->Fill(ds, "Departments");
sql = "INSERT INTO Departments VALUES ('M02', 'MIS', 'Room 105')";
da = gcnew OleDbDataAdapter(sql, conn);
da->Fill(ds, "Departments");
The above code will add a new record to the “Department” table.
DEPTID Department Location
S01 Sales Room 101
W01 Warehouse Room 102
A01 Administration Room 103
M02 MIS Room 105
The OleDbDataAdapter also includes the SelectCommand, InsertCommand, DeleteCommand,
UpdateCommand, and TableMappings properties to facilitate the loading and updating of data.
The Update() method of DataAdapter can send changes made in the DataSet back to the data
source. According Microsoft, Update() must work with Update, Insert and Delete query statement
of SQL to maintain database from the Server. The following illustrates how to use the Fill()
method to load the data into memory, insert a new record to the database, and then update the
DataSet in the memory with the Update() method.
String^ sql = "Select * from Departments";
OleDbDataAdapter^ da = gcnew OleDbDataAdapter(sql, conn);
DataSet^ ds = gcnew DataSet();
da->Fill(ds, "Departments");
sql = "INSERT INTO Departments VALUES ('M02', 'MIS', 'Room 105')";
da = gcnew OleDbDataAdapter(sql, conn);
da->Update(ds, "Departments");
The
SqlConnection
Class
While OleDbConnection is designed to access almost any kind of database, Microsoft also
introduces the SqlConnection class which is designed particularly for building a connection to a
SQL Server database, especially the Microsoft SQL. The notable advantage of SqlConnection is
performance because it is tuned specifically for accessing Sql Server.
Visual C++ Programming – Penn Wu, PhD 377
A SqlConnection object represents a unique session to a SQL Server data source. In order to test
this type of connection, you should install the Microsoft SQL Server (or at least the Express
version such as the “Microsoft SQL Server 2012 Express”). It is available for downloading at
http://www.microsoft.com/en-us/download/details.aspx?id=29062.
With a client/server database system, a SqlConnection-based connection is equivalent to a
network connection to the server. The following creates a SqlConnection instance named “conn”
using the SqlConnection() constructor. It assumes that the .MDF database file is stored in the
same directory as the source file. The “cdir” variable holds the path retrieved by the
GetCurrentDirectory() method of the Directory class which is the path of presently working
directory.
//get the path of presently working directory
String^ cdir = System::IO::Directory::GetCurrentDirectory();
String^ dbsrc = "Data Source=(local)\\SQLEXPRESS;AttachDbFilename=" +
cdir + "\\NORTHWND.MDF;Integrated Security=True;User
Instance=True;Connect Timeout=30;";
SqlConnection^ conn = gcnew SqlConnection(dbsrc);
The Open() method opens a database connection with the property settings specified by the
ConnectionString.
conn->Open();
SqlConnection is used together with SqlDataAdapter and SqlCommand to increase performance
when connecting to a SQL Server (not Microsoft Access) through a client-server based network.
The following illustrates how to create an instance of SqlDataAdapter.
SqlDataAdapter^ sqladp = gcnew SqlDataAdapter("select * from
Customers", conn);
The data returned by the SQL query needs a handle to implement them. The following example
uses DataTable to handle the data and display them in a tabular format through the use of
DataGridView.
DataTable^ dt1 = gcnew DataTable();
sqladp->Fill(dt1);
DataGridView^ datagridview1 = gcnew DataGridView();
datagridview1->DataSource = dt1;
The following is another example that demonstrates how to use DataSet to produce the same
result.
DataSet^ ds = gcnew DataSet();
sqladp->Fill(ds, "Customers");
DataGridView^ datagridview1 = gcnew DataGridView();
datagridview1->DataSource = gcnew BindingSource(ds, "Customers");
The SqlDataAdapter serves as a bridge between a DataSet and SQL Server for retrieving and
saving data. The SqlDataAdapter provides this bridge by mapping Fill, which changes the data in
the DataSet to match the data in the data source, and Update, which changes the data in the data
source to match the data in the DataSet, using the appropriate Transact-SQL statements against
the data source. When you create an instance of SqlConnection, all properties are set to their
initial values.
Visual C++ Programming – Penn Wu, PhD 378
The following is the complete code that access the “Customer” table of the NorthWnd database
and display all the data in a tabular format.
#using <System.dll>
#using <System.Drawing.dll>
#using <System.Windows.Forms.dll>
#using <System.Data.dll>
using namespace System;
using namespace System::Windows::Forms;
using namespace System::Drawing;
using namespace System::Data;
using namespace System::Data::SqlClient;
public ref class Form1: public Form {
public:
Form1() {
//get the path of presently working directory
String^ cdir = System::IO::Directory::GetCurrentDirectory();
String^ dbsrc = "Data
Source=(local)\\SQLEXPRESS;AttachDbFilename=" + cdir +
"\\NORTHWND.MDF;Integrated Security=True;User
Instance=True;Connect Timeout=30;";
SqlConnection^ conn = gcnew SqlConnection(dbsrc);
conn->Open();
SqlDataAdapter^ sqladp = gcnew SqlDataAdapter("select * from
Customers", conn);
DataSet^ ds = gcnew DataSet();
sqladp->Fill(ds, "Customers");
DataGridView^ datagridview1 = gcnew DataGridView();
datagridview1->DataSource = gcnew BindingSource(ds,
"Customers");
datagridview1->Location = Point(10, 10);
datagridview1->Size = Drawing::Size(770, 250);
this->Size = Drawing::Size(800, 300);
this->Controls->Add(datagridview1);
}
};
[STAThread]
int main() {
Application::Run(gcnew Form1);
}
The output looks:
Visual C++ Programming – Penn Wu, PhD 379
The SqlCommand class represents a Transact-SQL statement or stored procedure to execute
against a SQL Server database. The following creates a SqlCommand, and then executes it by
passing a string that is a Transact-SQL SELECT statement, and a string to use to connect to the
data source.
// Pass the connection to a command object
SqlCommand^ cmd = gcnew SqlCommand("select * from Customers",
conn);
..............
conn->Open();//Open the connection
The SqlDataReader class provides a way of reading a forward-only stream of rows from a SQL
Server database. To create a SqlDataReader, you must call the ExecuteReader() method of the
SqlCommand object, instead of directly using a constructor. For example,
// get query results
SqlDataReader^ rdr = cmd->ExecuteReader();
The query result is stored in the “rdr” array on a record-by-record basis, which meaning the “rdr”
store one set of record each time when it is used to handle the retrieved records. A repetition
structure, such as a while loop, can lead the code to read every set of record one after one. The
following uses the Read() method to read through the data, write it to the “str” variable, and loop
around till the end.
while (rdr->Read())
{
str += rdr[0] + "\n";
}
The NorthWnd database contains several tables: Products, Suppliers, Customers, Employees,
Shippers, Orders, and so on. The following is a sample code that list all the tables available in the
NorthWnd database. The SQL statement is: select table_name from
information_schema.tables.
#using <System.dll>
#using <System.Windows.Forms.dll>
#using <System.Data.dll>
using namespace System;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Data::SqlClient;
int main() {
//get the path of presently working directory
String^ cdir = System::IO::Directory::GetCurrentDirectory();
String^ dbsrc = "Data
Source=(local)\\SQLEXPRESS;AttachDbFilename=" + cdir +
"\\NORTHWND.MDF;Integrated Security=True;User
Instance=True;Connect Timeout=30;";
Visual C++ Programming – Penn Wu, PhD 380
SqlConnection^ conn = gcnew SqlConnection(dbsrc);
conn->Open();
// Pass the connection to a command object
SqlCommand^ cmd = gcnew SqlCommand("select table_name from
information_schema.tables", conn);
// get query results
SqlDataReader^ rdr = cmd->ExecuteReader();
String^ str = "";
while (rdr->Read())
{
str += rdr[0] + "\n";
}
rdr->Close();
conn->Close();
MessageBox::Show(str);
}
The following closes the SqlDataReader and then the SqlConnection as the above code ends the
program.
rdr->Close();
conn->Close();
The output looks:
The ADO.NET
ADO is short for ActiveX Data Objects. ADO.NET is the suite of data access technologies
included in the .NET Framework class libraries that provide access to relational data and XML. It
is the flexible data access layer that provides consistent access to a variety of data sources in a
disconnected architecture. Data sources, include SQL databases and data sources exposed through
OLE DB data access technology and XML. For the sake of simplicity, the sample included with
this article uses local XML files in place of what could be XML returned from Web service calls.
By using ADO.NET, you can make replacing the data provider completely transparent to the rest
of the application. For example, to write data to an XML file, use:
ds->WriteXml("departments.xml");
The WriteXml() method writes XML data, and optionally the schema, from the DataSet. The
ReadXml() method returns the XML representation of the data stored in the DataSet. For
example,
ds->ReadXml("departments.xml");
The following reads data in an XML file into a DataGridView through DataTable.
Visual C++ Programming – Penn Wu, PhD 381
ds->ReadXml("departments.xml");
DataTable^ dt = gcnew DataTable();
da->Fill(dt);
DataGridView^ datagridview1 = gcnew DataGridView();
datagridview1->DataSource = dt;
datagridview1->Location = Point(10, 10);
datagridview1->Size = Drawing::Size(770, 250);
this->Size = Drawing::Size(600, 300);
this->Controls->Add(datagridview1);
The following is a complete code. After executing, this program creates three files in the current
directory: departments.xml, deptmanagers.xml, and employees.xml.
#using <System.dll>
#using <System.Windows.Forms.dll>
#using <System.Drawing.dll>
#using <System.Xml.dll>
#using <System.Data.dll>
using namespace System;
using namespace System::Drawing;
using namespace System::Windows::Forms;
using namespace System::Xml;
using namespace System::Data;
using namespace System::Data::OleDb;
public ref class Form1: public Form {
public:
Form1() {
OleDbConnection^ conn = gcnew OleDbConnection();
conn->ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=emp.mdb";
OleDbDataAdapter^ da = gcnew OleDbDataAdapter("Select * from
Departments", conn);
DataSet^ ds = gcnew DataSet();
da->Fill(ds, "Departments");
ds->WriteXml("departments.xml");
da = gcnew OleDbDataAdapter("Select * from Deptmanagers", conn);
ds->WriteXml("deptmanagers.xml");
da = gcnew OleDbDataAdapter("Select * from Employees", conn);
ds->WriteXml("employees.xml");
ds->ReadXml("departments.xml");
DataTable^ dt = gcnew DataTable();
da->Fill(dt);
DataGridView^ datagridview1 = gcnew DataGridView();
datagridview1->DataSource = dt;
datagridview1->Location = Point(10, 10);
Visual C++ Programming – Penn Wu, PhD 382
datagridview1->Size = Drawing::Size(770, 250);
this->Size = Drawing::Size(600, 300);
this->Controls->Add(datagridview1);
conn->Close();
}
};
[STAThread]
int main() {
Application::Run(gcnew Form1);
}
Review
Questions
1. Which is the correct way to use the "ConnectionString" property and the "Jet.OLEDB.4.0"
driver to access a Microsoft Access database file named "client.mdb", assuming the database file
is stored in the "C:\temp" directory? ("conn" is an instance of OleDbConnection).
A. conn->ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=C:\temp\client.mdb";
B. conn->ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Directory=C:\temp; Data
Source=client.mdb";
C. conn->ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=C:\\temp\\client.mdb";
D. conn->ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Directory=C:\\temp;
Data Source=client.mdb";
2. Which creates an OleDbConnection object in Visual C++?
A. OleDbConnection^ conn = gcnew OleDbConnection();
B. OleDbConnection conn = gcnew OleDbConnection();
C. OleDbConnection^ conn = new OleDbConnection();
D. OleDbConnection conn = new OleDbConnection();
3. Which is the correct way to use the OleDbCommand to set an SQL statement for execution in
Visual C++?
A. OleDbCommand^ cmd = gcnew OleDbCommand("Select * from Students");
B. OleDbCommand cmd = gcnew OleDbCommand("Select * from Students");
C. OleDbCommand cmd = new OleDbCommand("Select * from Students");
D. OleDbCommand^ cmd = OleDbCommand("Select * from Students");
4. The __ class provides a set of data commands and a database connection that are used to fill the
DataSet and update the data source.
A. DbDataAdapter
B. OleDbDataAdapter
C. OleDbAdapter
D. OleDataAdapter
5. Given the following and a table named "Students", which represents all data in the field
(column) named "StudentID"?
OleDbCommand^ cmd = gcnew OleDbCommand("Select * from Students",
conn);
OleDbDataReader^ rd = cmd->ExecuteReader();
RecordID FirstName LastName StudentID
R2013579 Jennifer Lopez D99051297
R2013580 Nicole Kidman D01249360
Visual C++ Programming – Penn Wu, PhD 383
A. cmd[3]
B. rd[3]
C. cmd[0]rd[3]
D. rd[0]cmd[3]
6. Given the following code segment and a table named "Students", the output is __.
OleDbCommand^ cmd = gcnew OleDbCommand("Select * from Students",
conn);
OleDbDataReader^ rd = cmd->ExecuteReader();
MessageBox::Show(rd->GetName(2));
RecordID FirstName LastName StudentID
R2013579 Jennifer Lopez D99051297
R2013580 Nicole Kidman D01249360
A. RecordID
B. FirstName
C. LastName
D. StudentID
7. Given the following code segment, which will store the data returned by the SQL statement in
computer memory?
String^ sql = "Select * from Departments";
OleDbDataAdapter^ da = gcnew OleDbDataAdapter(sql, conn);
DataSet^ ds = gcnew DataSet();
A. da->Save(ds, "Departments");
B. da->Fill(ds, "Departments");
C. da->Load(ds, "Departments");
D. da->Read(ds, "Departments");
8. Which can produce the same result as the following statement does?
datagrid1->DataSource = ds->Tables["Departments"]->DefaultView;
A. dataGridView1->DataSource = gcnew DataSource(ds, "Departments");
B. dataGridView1->DataSource = gcnew BindingSource(ds, "Departments");
C. dataGridView1->DataSource = gcnew DataView(ds, "Departments");
D. dataGridView1->DataSource = gcnew BindingSource(ds, "Departments", DefaultView);
9. Which is the correct way to create an instance of SqlDataAdapter with a specific SQL statement
in Visual C++? (Assuming "conn" is an instance of SqlConnection)
A. SqlDataAdapter^ sqladp = SqlDataAdapter("select * from Customers", conn);
B. SqlDataAdapter^ sqladp = SqlDataAdapter(conn, "select * from Customers");
C. SqlDataAdapter^ sqladp = gcnew SqlDataAdapter("select * from Customers", conn);
D. SqlDataAdapter^ sqladp = gcnew SqlDataAdapter(conn, "select * from Customers");
10. Which can retrieve every record of data from the "Students" table on a one-by-one basis?
SqlCommand^ cmd = gcnew SqlCommand("select * from Students",
conn);
SqlDataReader^ rd = cmd->ExecuteReader();
A. while(read()) { }
B. while(read(rd)) { }
Visual C++ Programming – Penn Wu, PhD 384
C. while(rd->read()) { }
D. while(rd->read(cmd)) { }
Visual C++ Programming – Penn Wu, PhD 385
Lab #14 Connecting to Database
Learning Activity #1:
1. Create a directory called C:\cis223 if it does not exist.
2. Be sure to download the emp.mdb and save it to the C:\cis223 directory.
3. Be sure to determine what sort of Windows operating system you are using? __64 bit __ 32 bit.
4. Download and install the SQLEXPRESS 2012 from http://www.microsoft.com/en-
us/download/details.aspx?id=29062. [File name: Win64: SQLEXPR_x64 _ENU.exe, Win32: SQLEXPR32_x86 _ENU.exe]. Be sure to choose the “New SQL Server stand-alone installation or add feature
to an existing installation” option.
5. Launch the Developer Command Prompt (not the regular Command Prompt) and change to the C:\cis223
directory.
6. Type cd \cis223 and press [Enter] to change to the C:\cis223 directory.
7. Type notepad lab14_1.cpp and press [Enter] to use Notepad to create a new text file named lab14_1.cpp
with the following codes: #using <System.dll>
#using <System.Windows.Forms.dll>
#using <System.Data.dll>
#using <System.Drawing.dll>
using namespace System;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Data::OleDb;
int main()
{
Form^ form1 = gcnew Form;
Label^ label1 = gcnew Label;
label1->AutoSize = true;
form1->Controls->Add(label1);
Label^ label2 = gcnew Label;
label2->AutoSize = true;
form1->Controls->Add(label2);
Label^ label3 = gcnew Label;
label3->AutoSize = true;
form1->Controls->Add(label3);
OleDbConnection^ conn = gcnew OleDbConnection();
conn->ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=emp.mdb";
Visual C++ Programming – Penn Wu, PhD 386
conn->Open();
OleDbCommand^ cmd = gcnew OleDbCommand("Select * from Departments", conn);
OleDbDataReader^ rd = cmd->ExecuteReader();
label1->Text = rd->GetName(0) + "\n";
label2->Text = rd->GetName(1) + "\n";
label3->Text = rd->GetName(2) + "\n";
while (rd->Read())
{
label1->Text += rd[0] + "\n";
label2->Text += rd[1] + "\n";
label3->Text += rd[2] + "\n";
}
conn->Close();
label1->Location = System::Drawing::Point(10, 10);
label2->Location = System::Drawing::Point(label1->Left+label1->Width, 10);
label3->Location = System::Drawing::Point(label2->Left+label2->Width, 10);
Application::Run(form1);
}
8. Type cl /clr lab14_1.cpp /link /subsystem:windows /ENTRY:main and press [Enter] to compile
the code.
9. Type lab14_1.exe and press [Enter] to test the program. A sample output looks:
10. Download the “assignment template”, and rename it to lab14.doc if necessary. Capture a screen shot similar to
the above figure and paste it to the Word document named lab14.doc (or .docx).
Learning Activity #2: Adding new record
1. In the C:\223 directory, use Notepad to create a new text file named lab14_2.cpp with the following codes:
#using <System.dll>
#using <System.Drawing.dll>
#using <System.Windows.Forms.dll>
#using <System.Data.dll>
#include "InputBox.cpp"
using namespace System;
using namespace System::Windows::Forms;
using namespace System::Drawing;
using namespace System::Data;
using namespace System::Data::OleDb;
Visual C++ Programming – Penn Wu, PhD 387
int main()
{
String^ deptID = InputBox::Show("Enter department ID:");
String^ dept = InputBox::Show("Enter department:");
String^ room = InputBox::Show("Enter room number:");
Form^ form1 = gcnew Form;
OleDbConnection^ conn = gcnew OleDbConnection();
conn->ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=emp.mdb";
conn->Open();
String^ sql = "Select * from Departments";
OleDbDataAdapter^ da = gcnew OleDbDataAdapter(sql, conn);
DataSet^ ds = gcnew DataSet();
da->Fill(ds, "Departments");
sql = "INSERT INTO Departments VALUES ('" + deptID + "', '" + dept + "', '" + room
+ "')";
da = gcnew OleDbDataAdapter(sql, conn);
da->Fill(ds, "Departments");
ds->Clear();
// re-query
sql = "Select * from Departments";
da = gcnew OleDbDataAdapter(sql, conn);
da->Fill(ds, "Departments"); // with new record
DataGridView^ dataGridView1 = gcnew DataGridView;
dataGridView1->DataSource = gcnew BindingSource(ds, "Departments");
dataGridView1->Location = Point(10, 10);
dataGridView1->AutoSize = true;
form1->Controls->Add(dataGridView1);
conn->Close();
form1->Size = Size(400, 200);
Application::Run(form1);
}
2. Type cl /clr lab14_2.cpp /link /subsystem:windows /ENTRY:main and press [Enter] to compile
the code.
3. Type lab14_2 and press [Enter] to test the program. Add a few new records.
and and and
4. Capture a screen shot similar to the above figure and paste it to the Word document named lab14.doc
(or .docx).
Visual C++ Programming – Penn Wu, PhD 388
Learning Activity #3:
1. In the C:\223 directory, use Notepad to create a new text file named lab14_3.cpp with the following codes:
#using <System.dll>
#using <System.Drawing.dll>
#using <System.Windows.Forms.dll>
#using <System.Data.dll>
using namespace System;
using namespace System::Windows::Forms;
using namespace System::Drawing;
using namespace System::Data;
using namespace System::Data::OleDb;
public ref class Form1: public Form {
public:
OleDbConnection^ conn;
OleDbDataAdapter^ da;
DataSet^ ds;
DataGridView^ dataGridView1;
Form1() {
conn = gcnew OleDbConnection();
conn->ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=emp.mdb";
dataGridView1 = gcnew DataGridView;
dataGridView1->Location = Point(10, 10);
dataGridView1->AutoSize = true;
Button^ button1 = gcnew Button();
button1->Text = "DeptManager";
button1->Location = Point(10, 210);
button1->Click += gcnew EventHandler(this, &Form1::button1_Click);
Button^ button2 = gcnew Button();
button2->Text = "Employees";
button2->Location = Point(90, 210);
button2->Click += gcnew EventHandler(this, &Form1::button2_Click);
Button^ button3 = gcnew Button();
button3->Text = "Departments";
button3->Location = Point(170, 210);
button3->Click += gcnew EventHandler(this, &Form1::button3_Click);
this->Controls->Add(button1);
this->Controls->Add(button2);
this->Controls->Add(button3);
this->Controls->Add(dataGridView1);
this->AutoSize = true;
}
private: Void button1_Click(Object^ sender, EventArgs^ e) {
dataGridView1->Width = 100;
da = gcnew OleDbDataAdapter("Select * from Deptmanagers", conn);
ds = gcnew DataSet();
da->Fill(ds, "Deptmanagers");
dataGridView1->DataSource = ds->Tables["Deptmanagers"]->DefaultView;
this->Width = dataGridView1->Width;
}
Visual C++ Programming – Penn Wu, PhD 389
private: Void button2_Click(Object^ sender, EventArgs^ e) {
dataGridView1->Width = 100;
da = gcnew OleDbDataAdapter("Select * from Employees", conn);
ds = gcnew DataSet();
da->Fill(ds, "Employees");
dataGridView1->DataSource = ds->Tables["Employees"]->DefaultView;
this->Width = dataGridView1->Width;
}
private: Void button3_Click(Object^ sender, EventArgs^ e) {
dataGridView1->Width = 100;
da = gcnew OleDbDataAdapter("Select * from Departments", conn);
ds = gcnew DataSet();
da->Fill(ds, "Departments");
dataGridView1->DataSource = ds->Tables["Departments"]->DefaultView;
this->Width = dataGridView1->Width;
}
};
[STAThread]
int main() {
Application::Run(gcnew Form1);
}
2. Compile and test the program. Click every button to test the data retrieval.
3. Capture a screen shot similar to the above figure and paste it to the Word document named lab14.doc
(or .docx).
Learning Activity #4: Connect to NORTHWND.MDF database file
1. Be sure to download the NORTHWND.MDF file and save it to the directory in which the following source file
will be saved onto.
2. In the C:\223 directory, use Notepad to create a new text file named lab14_4.cpp with the following codes:
#using <System.dll>
#using <System.Drawing.dll>
#using <System.Windows.Forms.dll>
#using <System.Data.dll>
using namespace System;
using namespace System::Windows::Forms;
using namespace System::Drawing;
using namespace System::Data;
using namespace System::Data::SqlClient;
public ref class Form1: public Form {
public:
Form1() {
//get the path of presently working directory
String^ cdir = System::IO::Directory::GetCurrentDirectory();
Visual C++ Programming – Penn Wu, PhD 390
String^ dbsrc = "Data Source=(local)\\SQLEXPRESS;AttachDbFilename=" + cdir +
"\\NORTHWND.MDF;Integrated Security=True;User Instance=True;Connect Timeout=30;";
SqlConnection^ conn = gcnew SqlConnection(dbsrc);
conn->Open();
SqlDataAdapter^ sqladp = gcnew SqlDataAdapter("select * from Customers", conn);
DataTable^ dt1 = gcnew DataTable();
sqladp->Fill(dt1);
DataGridView^ datagridview1 = gcnew DataGridView();
datagridview1->DataSource = dt1;
datagridview1->Location = Point(10, 10);
datagridview1->Size = Drawing::Size(770, 250);
this->Size = Drawing::Size(800, 300);
this->Controls->Add(datagridview1);
}
};
[STAThread]
int main() {
Application::Run(gcnew Form1);
}
3. Compile and test the program.
4. Capture a screen shot similar to the above figure and paste it to the Word document named lab14.doc
(or .docx).
Learning Activity #5: Use ComboBox for keyword-based query (Northwnd)
1. In the C:\223 directory, use Notepad to create a new text file named lab14_5.cpp with the following codes:
#using <System.dll>
#using <System.Drawing.dll>
#using <System.Windows.Forms.dll>
#using <System.Data.dll>
using namespace System;
using namespace System::Windows::Forms;
using namespace System::Drawing;
using namespace System::Data;
using namespace System::Data::SqlClient;
public ref class Form1: public Form {
public:
Visual C++ Programming – Penn Wu, PhD 391
SqlDataReader^ rdr;
SqlCommand^ cmd;
SqlConnection^ conn;
ComboBox^ comboBox1;
String^ cid;
Label^ label1;
Form1() {
//get the path of presently working directory
String^ cdir = System::IO::Directory::GetCurrentDirectory();
String^ dbsrc = "Data Source=(local)\\SQLEXPRESS;AttachDbFilename=" + cdir +
"\\NORTHWND.MDF;Integrated Security=True;User Instance=True;Connect Timeout=30;";
conn = gcnew SqlConnection(dbsrc);
//Open the connection
conn->Open();
// Pass the connection to a command object
cmd = gcnew SqlCommand("select * from Customers", conn);
// get query results
rdr = cmd->ExecuteReader();
comboBox1 = gcnew ComboBox();
comboBox1->Text = "CustomerID";
comboBox1->Location = Point(10, 10);
comboBox1->SelectedIndexChanged += gcnew EventHandler(this,
&Form1::comboBox1_SelectedIndexChanged);
label1 = gcnew Label();
label1->Width = this->ClientSize.Width;
label1->Height = 200;
label1->Location = Point(10, 80);
Controls->Add(comboBox1);
Controls->Add(label1);
// print each record
while (rdr->Read()) {
comboBox1->Items->Add(rdr[0]);
}
rdr->Close();
}
private: Void comboBox1_SelectedIndexChanged(Object^ sender, EventArgs^ e)
{
cid = comboBox1->SelectedItem + "";
cmd = gcnew SqlCommand("select * from Customers where CustomerID = '" + cid +
"'", conn);
rdr = cmd->ExecuteReader();
String^ str = "Customer Information:\n";
while (rdr->Read()) {
str += "Company ID: " + rdr[0] + "\n";
str += "Company Name: " + rdr[1] + "\n";
str += "Contact Name: " + rdr[2] + "\n";
str += "Contact Title: " + rdr[3] + "\n";
Visual C++ Programming – Penn Wu, PhD 392
str += "Address: " + rdr[4] + "\n";
str += "City: " + rdr[5] + "\n";
str += "State/Province: " + rdr[6] + "\n";
str += "Post/Zip Code: " + rdr[7] + "\n";
str += "Country: " + rdr[8] + "\n";
str += "Phone: " + rdr[9] + "\n";
str += "Fax: " + rdr[10] + "\n";
}
label1->Text = str;
rdr->Close();
}
};
[STAThread]
int main() {
Application::Run(gcnew Form1);
}
2. Compile and test the program. Select any customer ID.
and
3. Capture a screen shot similar to the above figure and paste it to the Word document named lab14.doc
(or .docx).
Submittal
1. Complete all the 5 learning activities and the programming exercise in this lab.
2. Create a .zip file named lab14.zip containing ONLY the following self-executable files.
• lab14_1.exe
• lab14_2.exe
• lab14_3.exe
• lab14_4.exe
• lab14_5.exe
• lab14.doc (or lab14.docx or .pdf) [You may be given zero point if this Word document is missing]
3. Log in to Blackboard, and enter the course site.
4. Upload the zipped file to Question 11 of Assignment 14 as response.
5. Upload ex14.zip file to Question 12 as response. Note: You will not receive any credit if you submit file(s) to
the wrong question.
Programming Exercise:
1. Download the emp.mdb file if necessary.
2. Use Notepad to create a new file named ex14.cpp with the following heading lines (be sure to replace
YourFullNameHere with the correct one):
//File Name: ex14.cpp
//Programmer: YourFullNameHere
Visual C++ Programming – Penn Wu, PhD 393
3. Under the above two heading lines, write Visual C++ codes to use DataGridView to display the content of the
Employees table (of the emp.mdb file) in a Windows form (not message box), as shown below. Set the size of
form to be (450, 300). Set the size of DataGrid table to be (415, 250).
4. Download the “programming exercise template”, and rename it to ex14.doc if necessary. Capture Capture a
screen similar to the above figures and paste it to the Word document named “ex14.doc” (or .docx).
5. Compress the source file (ex14.cpp), executable code (ex14.exe), and Word document (ex14.doc) to a .zip file
named “ex14.zip”.
Grading Criteria:
• You must be the sole author of the codes.
• You must meet all the requirements in order to earn credits. You will receive zero if you use Visual Studio (C#)
IDE to generate the code.
• You must submit both source code (ex14.cpp) and the executable (ex14.exe) to earn credit.
• No partial credit is given.
Threaded Discussion
Note: Students are required to participate in the thread discussion on a weekly basis. Student must post at
least two messages as responses to the question every week. Each message must be posted on a
different date. Grading is based on quality of the message.
Question:
Class, this lecture discusses how to access a database file using Visual C++. In your opinion, is this a
good practice? Should a programmer avoid using Visual C++ to application to access a database file?
Why or why not? If you can, provide an example to support your perspective. [There is never a right-
or-wrong answer for this question. Please free feel to express your opinion.]
Be sure to use proper college level of writing. Do not use texting language.