How I do Update in SQL with c# - c#

I have this function in c#. When the FOR is call, a error appears in ExecuteNonQuery. The error is "ExecuteNonQuery requires the command to have a transaction when the connection assigned to the command is in a pending local transaction. The Transaction property of the command has not been initialized."
SqlConnection cnn = new SqlConnection(WebConfigurationManager.ConnectionStrings["strCnn"].ToString());
cnn.Open();
SqlTransaction trx = cnn.BeginTransaction();
try
{
SqlCommand cmd= new SqlCommand();
for (int j = 0; j < arr.Length; j++) {
cmd.CommandText = "UPDATE rc SET nc= " + arr[j].Col3 + " WHERE cr = " + arr[j].Col1;
cmd.Connection = cnn;
cmd.ExecuteNonQuery();
}
trx.Commit();
return 1;
}
catch (SqlException ex)
{
try
{
trx.Rollback();
return 0;
}
catch (Exception exRollback)
{
return 0;
}
}

This error message shows that you have opened a transaction and it is still open at the point of executing ExecuteNonQuery,
You are executing ExecuteNonQuery before commitment of transaction.
Define
comando.Transaction = trx;
So that ExecuteNonQuery will be executed on the same transaction.

Use
// Create command on transaction and automatically assign open transaction
var comando = conexao.CreateCommand()
or assign the transaction to the command.
// Create command
var comando = new SqlCommand();
// and assign transaction manually
comando.Transaction = trx;

you forgot to set transaction
comando.Transaction = trx;

You need to assign the transaction to the command, like so:
SqlCommand comando = new SqlCommand();
comando.Transaction = trx;
I would also recommend setting the Connection property outside of the for loop too, so you code would look like this:
SqlCommand comando = new SqlCommand();
comando.Transaction = trx;
comando.Connection = conexao;
for (int j = 0; j < arr.Length; j++) {
comando.CommandText = "UPDATE RECURSO_CLIENTE SET NM_CLIENTE = " + arr[j].Col3 + " WHERE CD_RECURSO = " + arr[j].Col1;
comando.ExecuteNonQuery();
}
trx.Commit();

You need to set SqlCommand's transaction property.
SqlCommand comando = new SqlCommand();
comando.Transaction = trx;

Your sqlCommand doesn't know about your transaction.
Here's a copy-paste fix:
SqlConnection conexao = new SqlConnection(WebConfigurationManager.ConnectionStrings["strConexao"].ToString());
conexao.Open();
SqlTransaction trx = conexao.BeginTransaction();
try
{
for (int j = 0; j < arr.Length; j++) {
var commandText = "UPDATE RECURSO_CLIENTE SET NM_CLIENTE = " + arr[j].Col3 + " WHERE CD_RECURSO = " + arr[j].Col1;
SqlCommand comando = new SqlCommand(commandText, conexao, trx);
comando.ExecuteNonQuery();
}
trx.Commit();
return 1;
}
catch (SqlException ex)
{
try
{
trx.Rollback();
return 0;
}
catch (Exception exRollback)
{
return 0;
}
}

As has been pointed out, you never assign your transaction to the command. However there are a few other points I have picked up on.
First and foremost USE PARAMETRISED QUERIES, they will improve performace, type safety and most importantly save you from SQL Injection Attacks.
So instead of:
comando.CommandText = "UPDATE RECURSO_CLIENTE SET NM_CLIENTE = " + arr[j].Col3 + " WHERE CD_RECURSO = " + arr[j].Col1;
You would use:
comando.CommandText = "UPDATE RECURSO_CLIENTE SET NM_CLIENTE = #Col3 WHERE CD_RECURSO = #Col1";
comando.Parameters.AddWithValue("#Col3", arr[j].Col3);
comando.Parameters.AddWithValue("#Col1", arr[j].Col1);
Secondly, wrap your sql command object with a using wrapper to ensure it is properly dispose of, there is no benefit from reusing the same object over and over again (and this can cause problems):
for (int j = 0; j < arr.Length; j++)
{
using (var comando = new SqlCommand("UPDATE RECURSO_CLIENTE SET NM_CLIENTE = #Col3 WHERE CD_RECURSO = #Col1", conexao))
{
comando.Transaction = trx;
comando.Parameters.AddWithValue("#Col3", arr[j].Col3);
comando.Parameters.AddWithValue("#Col1", arr[j].Col1);
comando.ExecuteNonQuery();
}
}
Finally, if you are using SQL-Server 2008+ you can use Table valued Parameters to do this update in a single query:
You first need a type
CREATE TABLE YourTypeName AS TABLE (Col1 INT, Col3 INT);
Then your update statement would be something like:
DECLARE #UpdateValues AS YourTypeName;
MERGE RECURSO_CLIENTE rc
USING #UpdateValues u
ON rc.CD_RECURSO = u.Col1
WHEN MATCHED UPDATE
SET NM_CLIENTE = u.Col3;
This means a single statement and you don't need to use explicit transactions. (You might wonder why I have used merge instead of UPDATE, here is why). So putting it all together you would get:
var dataTable = new DataTable();
dataTable.Columns.Add("Col1", typeof(int));
dataTable.Columns.Add("Col3", typeof(int));
for (int j = 0; j < arr.Length; j++)
{
var newRow = dataTable.NewRow();
newRow[0] = arr[j].Col1;
newRow[1] = arr[j].Col3;
dataTable.Rows.Add(newRow);
}
string sql = #" MERGE RECURSO_CLIENTE rc
USING #UpdateValues u
ON rc.CD_RECURSO = u.Col1
WHEN MATCHED UPDATE
SET NM_CLIENTE = u.Col3;";
using (var conexao = new SqlConnection(WebConfigurationManager.ConnectionStrings["strConexao"].ToString()))
using (var comando = new SqlCommand(sql, conexao))
{
conexao.Open();
var tableParam = new SqlParameter("#UpdateValues", SqlDbType.Structured);
tableParam.TypeName = "#YourTypeName";
tableParam.Value = dataTable;
comando.Parameters.Add(tableParam);
comando.ExecuteNonQuery();
}

Related

Can't insert data into SQL Server table in a loop using c#

As shown in the screenshot, I was trying to insert data into a table. The 1st iteration works fine, but the 2nd iteration throws an error/exception.
What is wrong with my code?
Below is the code.
SqlConnection sqlconn = new SqlConnection(sqlconnectionstring);
// sqlconn.Open();
string InsertData = "INSERT INTO AUStagAPITestData ([TestSuite], [TestCase],[Status], [Info], [Time], [IsArchived], [DateTime]) VALUES (#TestSuite, #TestCase, #Status, #Info, #Time, #IsArchived, #DateTime)";
SqlCommand Insertcmd = new SqlCommand(InsertData, sqlconn);
for (int j = 1; j < TDData.Length; j +=5)
{
sqlconn.Open();
string TestSuite = TDData[j];
string TestCase = TDData[j+1];
string Status = TDData[j + 2];
string Info = TDData[j + 3];
string Time = TDData[j + 4];
Insertcmd.Parameters.AddWithValue("#TestSuite", TestSuite);
Insertcmd.Parameters.AddWithValue("#TestCase", TestCase);
Insertcmd.Parameters.AddWithValue("#Status", Status);
Insertcmd.Parameters.AddWithValue("#Info", Info);
Insertcmd.Parameters.AddWithValue("#Time", Time);
Insertcmd.Parameters.AddWithValue("#IsArchived", "1");
Insertcmd.Parameters.AddWithValue("#DateTime", DateTime.Now);
Insertcmd.ExecuteNonQuery();
sqlconn.Close();
}
What you really should do is:
create the list of parameter objects once, before the loop
during the loop, only set their values
Something like this:
string InsertData = "INSERT INTO AUStagAPITestData ([TestSuite], [TestCase],[Status], [Info], [Time], [IsArchived], [DateTime]) VALUES (#TestSuite, #TestCase, #Status, #Info, #Time, #IsArchived, #DateTime)";
// put your connection and command into *USING* blocks to properly dispose of them
using (SqlConnection sqlconn = new SqlConnection(sqlconnectionstring))
using (SqlCommand Insertcmd = new SqlCommand(InsertData, sqlconn))
{
// create the parameters **ONCE** and define their datatypes
// I have only *guessed* what the datatypes could be - adapt as needed
Insertcmd.Parameters.Add("#TestSuite", SqlDbType.VarChar, 50);
Insertcmd.Parameters.Add("#TestCase", SqlDbType.VarChar, 50);
Insertcmd.Parameters.Add("#Status", SqlDbType.VarChar, 50);
Insertcmd.Parameters.Add("#Info", SqlDbType.VarChar, 50);
Insertcmd.Parameters.Add("#Time", SqlDbType.Time);
Insertcmd.Parameters.Add("#IsArchived", SqlDbType.Boolean);
Insertcmd.Parameters.Add("#DateTime", SqlDbType.DateTime);
sqlconn.Open();
// now loop over the data and set the parameter values
for (int j = 1; j < TDData.Length; j +=5)
{
string TestSuite = TDData[j];
string TestCase = TDData[j+1];
string Status = TDData[j + 2];
string Info = TDData[j + 3];
string Time = TDData[j + 4];
Insertcmd.Parameters["#TestSuite"].Value = TestSuite;
Insertcmd.Parameters["#TestCase"].Value = TestCase;
Insertcmd.Parameters["#Status"].Value = Status;
Insertcmd.Parameters["#Info"].Value = Info;
Insertcmd.Parameters["#Time"].Value = Time;
Insertcmd.Parameters["#IsArchived"].Value = true;
Insertcmd.Parameters["#DateTime"].Value = DateTime.Now;
// execute the query in the loop
Insertcmd.ExecuteNonQuery();
}
sqlconn.Close();
}
It's complaining you have already added:
Insertcmd.Parameters.AddWithValue("#TestSuite
The fix is to instantiate a new SqlCommand each iteration:
for (int j = 1; j < TDData.Length; j +=5)
{
sqlconn.Open();
SqlCommand Insertcmd = new SqlCommand(InsertData, sqlconn);
string TestSuite= TDData[j];
try to move sqlconn.Open() & sqlconn.Close() out of the for loop and renew sqlcommand object.
sqlconn.Open();
for (int j = 1; j < TDData.Length; j += 5)
{
SqlCommand Insertcmd = new SqlCommand(InsertData, sqlconn);
string TestSuite = TDData[j];
...
}
sqlconn.Close();
Check this example based on your code:
string connectionString, queryInsert;
string[] arrayData = new string[10];
connectionString = ConfigurationManager.ConnectionStrings["DbConn"].ConnectionString;
queryInsert = #"
INSERT INTO AUStagAPITestData
(
[TestSuite], [TestCase], [Status], [Info], [Time], [IsArchived], [DateTime]
)
VALUES (
#TestSuite, #TestCase, #Status, #Info, #Time, #IsArchived, #DateTime
)
";
using (SqlConnection connection = new SqlConnection(connectionString))
using (SqlCommand command = new SqlCommand(queryInsert, connection))
{
string testSuite, testCase, status, info, time;
connection.Open();
for (int j = 1; j < arrayData.Length; j += 5)
{
testSuite = arrayData[j];
testCase = arrayData[j + 1];
status = arrayData[j + 2];
info = arrayData[j + 3];
time = arrayData[j + 4];
command.Parameters.AddWithValue("#TestSuite", testSuite);
command.Parameters.AddWithValue("#TestCase", testCase);
command.Parameters.AddWithValue("#Status", status);
command.Parameters.AddWithValue("#Info", info);
command.Parameters.AddWithValue("#Time", time);
command.Parameters.AddWithValue("#IsArchived", "1");
command.Parameters.AddWithValue("#DateTime", DateTime.Now);
command.ExecuteNonQuery();
// To Clear parameters
command.Parameters.Clear();
}
// no need to close a disposed object since dispose will call close
}
You can use Insertcmd.Parameters.Clear() inside your for loop.
As I wrote in the comments, I would use a stored procedure with a table valued parameter instead of inserting the records one by one. This has the advantage of only making one round trip from your application code to your database.
However, it also has a disadvantage - if one row fails for any reason (say, violating a constraint), the entire insert will fail.
Having said that, in order to use a table valued parameter you should first create a user defined table type. Note that I'm guessing your columns data types here, you might need to change them:
CREATE TYPE dbo.tt_TestData (
[TestSuite] int, -- I'm guessing foreign keys
[TestCase] int,
[Status] int,
[Info] nvarchar(255),
[Time] time,
[IsArchived] bit,
[DateTime] datetime
);
GO
After you've done that, you can create your stored procedure:
CREATE PROCEDURE stp_AUStagAPITestData_Insert
(
#Data dbo.tt_TestData READONLY -- Note: Readonly is a must!
)
AS
INSERT INTO AUStagAPITestData (
[TestSuite],
[TestCase],
[Status],
[Info],
[Time],
[IsArchived],
[DateTime]
)
SELECT
[TestSuite],
[TestCase],
[Status],
[Info],
[Time],
[IsArchived],
[DateTime]
FROM #Data;
GO
Now, to execute this stored procedure using ADO.Net, you will need to create a data table for your data, and send it as a paramameter of type SqlDbType.Structured to the stored procedure:
using (var sqlconn = new SqlConnection(sqlconnectionstring))
{
using (var Insertcmd = new SqlCommand("stp_AUStagAPITestData_Insert", sqlconn))
{
// Create the data table
using (var dt = new DataTable())
{
dt.Columns.Add("TestSuite", typeof(int));
dt.Columns.Add("TestCase", typeof(int));
dt.Columns.Add("Status", typeof(int));
dt.Columns.Add("Info", typeof(string));
dt.Columns.Add("Time", typeof(DateTime));
dt.Columns.Add("IsArchived", typeof(bool));
dt.Columns.Add("DateTime", typeof(DateTime));
// Populate the data table from the TDData string array
for (int j = 1; j < TDData.Length; j += 5)
{
dt.Rows.Add
(
TDData[j], // TestSuite
TDData[j + 1], // TestCase
TDData[j + 2], // Status
TDData[j + 3], // Info
TDData[j + 4], // Time
true, // IsArchived
DateTime.Now // DateTime
);
}
Insertcmd.CommandType = CommandType.StoredProcedure;
Insertcmd.Parameters.Add("#Data", SqlDbType.Structured).Value = dt;
try
{
sqlconn.Open();
Insertcmd.ExecuteNonQuery();
}
catch (Exception e)
{
// Exception handling code goes here...
}
}
}
}

store sheetname in table

I have the following code . I can extract all data from all data existing in sheets in a workbook and the name of the sheet
foreach (var sheetName in GetExcelSheetNames(connectionString))
{
using (OleDbConnection con = new OleDbConnection(connectionString))
{
var dataTable = new DataTable();
string query = string.Format("SELECT {0} as sheetName, * FROM [{0}]", sheetName);
con.Open();
OleDbDataAdapter adapter = new OleDbDataAdapter(query, con);
adapter.Fill(dataTable);
ds.Tables.Add(dataTable);
}
}
Then I write the following code to store data in a table in sql server
if (ds.Tables.Count > 0)
{
foreach (DataTable dt in ds.Tables)
{
using (SqlConnection con = new SqlConnection(consString))
{
con.Open();
for (int i = 2; i < dt.Rows.Count; i++)
{
for (int j = 1; j < dt.Columns.Count; j += 3)
{
//Here the problem
SqlCommand command = new SqlCommand( what should I write? ) ;
command.ExecuteNonQuery();
}
}
con.Close();
}
}
My problem is how to store sheetname in a table [Obj CA]?
I think your
"...VALUES('sheetname" + dt.Rows[0][j].ToString() + "' )
should be
"...VALUES('sheetname', '" + dt.Rows[0][j].ToString() + "' )
since you try to insert two values but you didn't seperate them with a comma.
But as a better way, use parameterized queries. This kind of string concatenations are open for SQL Injection attacks.
var command = new SqlCommand(#"INSERT INTO [Obj CA] (sheetname, [Rayon])
VALUES('sheetname', #rayon"), con);
for (int i = 2; i < dt.Rows.Count; i++)
{
for (int j = 1; j < dt.Columns.Count; j += 3)
{
command.Parameters.Clear();
command.Parameters.AddWithValue("#rayon", dt.Rows[0][j].ToString());
command.ExecuteNonQuery();
}
}
By the way, since I didn't know your column types, I used AddWithValue as an example but you don't. This method may generate unexpected results sometimes. Use Add overload to specify your parameter type and it's size.
Also I strongly suspect you should change your column definition order as well like (sheetname, [Rayon]) in your INSERT statement.

SQL Transaction not committing to database

I am writing my first SQL transaction code and have scoured stackoverflow to make sure I've done it right. The basic idea of the project is to get an email, parse it into a RawDatum object, then write the contents of the object to the SQL database. I was hoping to commit the new rows in batches of 100.
I have the code running without errors, but nothing is being actually written to the database.
I have a local DB (MS SQL Server Express). I have a few things commented out for testing purposes. What am I doing wrong?
using (SqlConnection connection = new SqlConnection(Properties.Settings.Default.MissionMetricsConnectionString))
{
connection.Open();
SqlCommand command = connection.CreateCommand();
command.CommandType = CommandType.Text;
command.CommandText = #"INSERT INTO RawData (MessageUID, DateTime, Attribute, DigitalValue, AnalogValue) VALUES (#MessageUID, #DateTime, #Attribute, #DigitalValue, #AnalogValue)";
command.Parameters.Add("#MessageUID", SqlDbType.Int);
command.Parameters.Add("#DateTime", SqlDbType.DateTime);
command.Parameters.Add("#Attribute", SqlDbType.Text);
command.Parameters.Add("#DigitalValue", SqlDbType.Bit);
command.Parameters.Add("#AnalogValue", SqlDbType.Float);
command.Connection = connection;
RawDatum currentDatum = null;
int uid;
List<int> uidsToDelete = new List<int>();
int numLoops = 1;//(int)(ids.Length / loopSize) + 1;
for (var loopIndex = 0; loopIndex < numLoops; loopIndex++)
{
int startIndex = loopIndex * loopSize;
int endIndex = 10;// Math.Min((loopIndex + 1) * loopSize, ids.Length);
using (SqlTransaction transaction = connection.BeginTransaction())
{
try
{
command.Transaction = transaction;
for (int i = startIndex; i < endIndex; i++)
{
msg = inbox.Fetch.MessageObject(ids[i]);
uid = inbox.Fetch.Uid(ids[i]);
if (msg.Subject == "[METRICS]")
{
currentDatum = new RawDatum(uid, msg.Date, msg.BodyText.TextStripped);
command.Parameters["#MessageUID"].Value = currentDatum.MessageUid;
command.Parameters["#DateTime"].Value = currentDatum.DateTime;
command.Parameters["#Attribute"].Value = currentDatum.Attribute;
command.Parameters["#DigitalValue"].Value = currentDatum.DigitalValue;
command.Parameters["#AnalogValue"].Value = currentDatum.AnalogValue;
int queryResult = command.ExecuteNonQuery();
if (queryResult != 1)
{
throw new InvalidProgramException();
}
}
uidsToDelete.Add(uid);
}
transaction.Commit();
//Delete(uidsToDelete);
output[1] += uidsToDelete.Count;
uidsToDelete.Clear();
}
catch
{
transaction.Rollback();
output[0] += 1;
output[2] += endIndex - startIndex;
}
}
}
connection.Close();
}

How to execute a ExecuteNonQuery with List parameters in Where Clause

My code looks like this:
var settings = ConfigurationManager.ConnectionStrings["InsurableRiskDB"];
string server = ConfigurationManager.AppSettings["Server"];
string cs = String.Format(ConfigurationManager.AppSettings[settings.ProviderName], ConfigurationManager.AppSettings[server]);
SqlConnection connection = new SqlConnection(cs);
string PolicyKeys = "";
for (int i = 0; i < keys.Count(); i++)
{
if (i == keys.Count() - 1)
PolicyKeys += keys[i] ;
else
PolicyKeys += keys[i] + ", ";
}
//have to change the code to pull the user's NBK.
string user = "'DATALOAD'";
const string updateQuery = #"UPDATE [InsurableRisk].[dbo].[Policy]
SET [InsuranceCarrierKey] = #ToKey
,[AuditUser] = #User
,[AuditDate] = SYSDATETIME()
WHERE PolicyKey in (#PolicyKeys) and InsuranceCarrierKey = #FromKey";
using (connection)
{
using (SqlCommand dataCommand = new SqlCommand(updateQuery, connection))
{
dataCommand.Parameters.AddWithValue("#ToKey", toKey);
dataCommand.Parameters.AddWithValue("#User", user);
dataCommand.Parameters.AddWithValue("#PolicyKeys", PolicyKeys);
dataCommand.Parameters.AddWithValue("#FromKey", fromKey);
connection.Open();
dataCommand.ExecuteNonQuery();
connection.Close();
}
}
res = true;
}
catch (Exception ex)
{
MessageBox.Show("There is an error while try in save the changes " + ex.Message, "Error Message", MessageBoxButtons.OKCancel);
res = false;
}
return res;
Now, when i run this code, it says query is unable to execute. It throws and exception stating, it is unable to convert NVarchar to int for variable #PolicyKeys
Any suggestions as to what i am missing in this code?
Typically, in SQL you'd write an IN statement like this:
WHERE SomeColumn IN ('A', 'B', 'C')
What you're doing is the equivalent of this in SQL (which won't work):
WHERE SomeColumn IN ('A, B, C')
Change your SQL statement accordingly: (modified from this answer)
WHERE PolicyKey in ({0})
And then add your parameters in a loop, like this:
var parameters = new string[keys.Count()];
for (int i = 0; i < keys.Count(); i++)
{
parameters[i] = string.Format("#Key{0}", i);
cmd.Parameters.AddWithValue(parameters[i], keys[i]);
}
cmd.CommandText = string.Format(updateQuery, string.Join(", ", parameters));

How to find Max element in SQLite?

I need select the maximum ID of PolygonId column. I save my data like this
string sql = "create table Polygons (PolygonId int, PointId int, X double, Y double)";
// Выполнение нашей команды
using (SQLiteCommand command = new SQLiteCommand(sql, m_dbConnection))
{
command.ExecuteNonQuery();
}
int pointId = 1;
for (int i = 0; i < listOfCustomPolygons.Count; i++)
for (int j = 0; j < listOfCustomPolygons[i].listOfVertexes.Count; j++)
{
string strSQL =
string.Format("INSERT INTO Polygons (PolygonId,PointId,X,Y) Values ('{0}','{1}','{2}','{3}')",
i+1,pointId,listOfCustomPolygons[i].listOfVertexes[j].X,
listOfCustomPolygons[i].listOfVertexes[j].Y );
pointId++;
using (SQLiteCommand insertCommand = new SQLiteCommand(strSQL, m_dbConnection))
{
insertCommand.ExecuteNonQuery();
}
}
After this I want select the max value from table Polygons and column PolygonId, but I got an IndexOutOfRangeException. How a can solve this problem?
using (SQLiteConnection connection = new SQLiteConnection("Data Source=" + openFileDialog.FileName + ";Version=3;"))
{
connection.Open();
string selectMaxId = "Select Max(PolygonId) From Polygons";
string selectQuery = "Select * From Polygons";
SQLiteCommand selectMaxCmd = new SQLiteCommand(selectMaxId,connection);
SQLiteDataReader dataReader = selectMaxCmd.ExecuteReader();
int maxId = Convert.ToInt32(dataReader["Select Max(PolygonId) From Polygons"]); // This is don't work! Why?
I found out the solution! It should look like
string selectMaxId = "Select Max(PolygonId) From Polygons";
SQLiteCommand selectMaxCmd = new SQLiteCommand(selectMaxId,connection);
object val = selectMaxCmd.ExecuteScalar();
int maxId = int.Parse(val.ToString());
I hope it can help somebody who face with similar problem)
First of all don't create table every time you run your code :) But you probably know that
You type like this:
int maxId = Convert.ToInt32(dataReader["Select Max(PolygonId) From Polygons"]);
Try this:
string selectMaxId = "Select Max(PolygonId) From Polygons";
SQLiteCommand selectMaxCmd = new SQLiteCommand(selectMaxId,connection);
SQLiteDataReader dataReader = selectMaxCmd.ExecuteReader();
int maxID = -1;
while(dataReader.read())
{
maxID = (int)dataReader.GetValue(0);
}
//This Works for me in WPF C#:
int MaxNum=0;
sqliteCon.Open();
string Query = "SELECT MAX(Promo_No)FROM Promo_File";
SQLiteCommand createCommand = new SQLiteCommand(Query, sqliteCon);
SQLiteDataReader DR = createCommand.ExecuteReader();
while (DR.Read())
{
MaxNum = DR.GetInt16(0);
}
sqliteCon.Close();
I had the same problem!
You have to learn the difference method of SQLiteCommand.
1.SQLiteCommand.ExecuteReader(). Get a SqlDataReader.
2.SQLiteCommand.ExecuteScalar(). Get a single value from the database.
Microsoft Doc:
cmd.CommandText = "SELECT COUNT(*) FROM dbo.region";
Int32 count = (Int32) cmd.ExecuteScalar();

Categories

Resources