Simple way to check how many rows I have in my database - c#

I'm connected to a database through the SqlConnection class. Is there any simple why to check how many rows are in the database or do I have to create a SqlDataReader and increment till the last row in it ?

I assume "rows in the database" actually means "rows in the table".
You should use Count and SqlCommand.ExecuteScalar:
int rowCount = 0;
using(var con = new SqlConnection(connectionsString))
using (var cmd = new SqlCommand("SELECT COUNT(*) FROM dbo.TableName", con))
{
try
{
con.Open();
rowCount = (int) cmd.ExecuteScalar();
} catch (Exception ex)
{
// log this exception or do something else useful, otherwise it's better to...
throw;
}
}

Related

data reader is reading the roll numbers twice as I open it second time & thrice as I open it third time

Dear Coders!
Hope u all are fine there.I am working on a school's Software.There are two buttons on Main Screen;Student Info List & Update Student Info.On Clicking Update Student Info , it opens the screen where you can edit the Student's Infromation.When I click on the combo box to select the Roll No.It shows all good.But when I go back to Main Screen & Click on Student Info List;It opens the data grid view(containing all information of the students).And then again I open to Update the Information,It shows the Roll No twice.As repeated the steps,it shows the roll no increasing.
Pictures are given in the form of link.
Code is given below.Any help will be appriciated.
Thank you
[try
{
int i = 0;
using (SqlConnection sqlCon = new SqlConnection(Form1.connectionString))
{
string commandString = "SELECT RollNO FROM Student1";
// MessageBox.Show(commandString);
SqlCommand sqlCmd = new SqlCommand(commandString, sqlCon);
sqlCon.Open();
SqlDataReader dr = sqlCmd.ExecuteReader();
while (dr.Read())
{
i = 1;
comboBox3.Items.Add(dr\[0\]);
}
dr.Close();
}
if (i == 0)
{
MessageBox.Show("Database Error");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}][2]
Actually each time you are filling your combobox you are not clearing previous items call I have modified your code try this one
try
{
int i = 0;
using (SqlConnection sqlCon = new SqlConnection(Form1.connectionString))
{
string commandString = "SELECT RollNO FROM Student1";
comboBox3.Items.Clear(); //first clear previous items then refill
// MessageBox.Show(commandString);
SqlCommand sqlCmd = new SqlCommand(commandString, sqlCon);
sqlCon.Open();
SqlDataReader dr = sqlCmd.ExecuteReader();
while (dr.Read())
{
i = 1;
comboBox3.Items.Add(dr[0]);
}
dr.Close();
}
if (i == 0)
{
MessageBox.Show("Database Error");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}

C# ASP.Net Processing Issue - Reading Table While Deleting Rows

Simply, I have an application that has one page that deletes and then re-adds/refreshes the records into a table every 30 seconds. I have another page that runs every 45 seconds that reads the table data and builds a chart.
The problem is, in the read/view page, every once in a while I get a 0 value (from a max count) and the chart shows nothing. I have a feeling that this is happening because the read is being done at the exact same time the delete page has deleted all the records in the table but has not yet refreshed/re-added them.
Is there a way in my application I can hold off on the read when the table is being refreshed?
Best Regards,
Andy
C#
ASP.Net 4.5
SQL Server 2012
My code below is run in an ASP.Net 4.5 built Windows service. It deletes all records in the ActualPlot table and then refreshes/adds new records from a text file every 30 seconds. I basically need to block (lock?) any user from reading the ActualPlot table while the records are being deleted and refreshed. Can you PLEASE help me change my code to do this?
private void timer1_Tick(object sender, ElapsedEventArgs e)
{
// Open the SAP text files, clear the data in the tables and repopulate the new SAP data into the tables.
var cnnString = ConfigurationManager.ConnectionStrings["TaktBoardsConnectionString"].ConnectionString;
SqlConnection conn = new SqlConnection(cnnString);
SqlConnection conndetail = new SqlConnection(cnnString);
SqlConnection connEdit = new SqlConnection(cnnString);
SqlCommand cmdGetProductFile = new SqlCommand();
SqlDataReader reader;
string sql;
// Delete all the records from the ActualPlot and the ActualPlotPreload tables. We are going to repopulate them with the data from the text file.
sql = "DELETE FROM ActualPlotPreload";
try
{
conn.Open();
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.ExecuteNonQuery();
}
catch (System.Data.SqlClient.SqlException ex)
{
string msg = "Delete Error:";
msg += ex.Message;
Library.WriteErrorLog(msg);
}
finally
{
conn.Close();
}
sql = "DELETE FROM ActualPlot";
try
{
conn.Open();
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.ExecuteNonQuery();
}
catch (System.Data.SqlClient.SqlException ex)
{
string msg = "Delete Error:";
msg += ex.Message;
Library.WriteErrorLog(msg);
}
finally
{
conn.Close();
}
// Read the SAP text file and load the data into the ActualPlotPreload table
sql = "SELECT DISTINCT [BoardName], [ProductFile], [ProductFileIdent] FROM [TaktBoards].[dbo].[TaktBoard] ";
sql = sql + "JOIN [TaktBoards].[dbo].[Product] ON [Product].[ProductID] = [TaktBoard].[ProductID]";
cmdGetProductFile.CommandText = sql;
cmdGetProductFile.CommandType = CommandType.Text;
cmdGetProductFile.Connection = conn;
conn.Open();
reader = cmdGetProductFile.ExecuteReader();
string DBProductFile = "";
string DBTischID = "";
string filepath = "";
string[] cellvalues;
DateTime dt, DateCheckNotMidnightShift;
DateTime ldSAPFileLastMod = DateTime.Now;
string MyDateString;
int FileRecordCount = 1;
while (reader.Read())
{
DBProductFile = (string)reader["ProductFile"];
DBTischID = (string)reader["ProductFileIdent"];
filepath = "c:\\inetpub\\wwwroot\\WebApps\\TaktBoard\\FilesFromSAP\\" + DBProductFile;
FileInfo fileInfo = new FileInfo(filepath); // Open file
ldSAPFileLastMod = fileInfo.LastWriteTime; // Get last time modified
try
{
StreamReader sr = new StreamReader(filepath);
FileRecordCount = 1;
// Populate the AcutalPlotPreload table from with the dates from the SAP text file.
sql = "INSERT into ActualPlotPreload (ActualDate, TischID) values (#ActualDate, #TischID)";
while (!sr.EndOfStream)
{
cellvalues = sr.ReadLine().Split(';');
if (FileRecordCount > 1 & cellvalues[7] != "")
{
MyDateString = cellvalues[7];
DateTime ldDateCheck = DateTime.ParseExact(MyDateString, "M/dd/yyyy", null);
DateTime dateNow = DateTime.Now;
string lsDateString = dateNow.Month + "/" + dateNow.Day.ToString("d2") + "/" + dateNow.Year;
DateTime ldCurrentDate = DateTime.ParseExact(lsDateString, "M/dd/yyyy", null);
string lsTischID = cellvalues[119];
if (ldDateCheck == ldCurrentDate)
{
try
{
conndetail.Open();
SqlCommand cmd = new SqlCommand(sql, conndetail);
cmd.Parameters.Add("#ActualDate", SqlDbType.DateTime);
cmd.Parameters.Add("#TischID", SqlDbType.VarChar);
cmd.Parameters["#TischID"].Value = cellvalues[119];
MyDateString = cellvalues[7] + " " + cellvalues[55];
dt = DateTime.ParseExact(MyDateString, "M/dd/yyyy H:mm:ss", null);
cmd.Parameters["#ActualDate"].Value = dt;
// Ignore any midnight shift (12am to 3/4am) units built.
DateCheckNotMidnightShift = DateTime.ParseExact(cellvalues[7] + " 6:00:00", "M/dd/yyyy H:mm:ss", null);
if (dt >= DateCheckNotMidnightShift)
{
cmd.ExecuteNonQuery();
}
}
catch (System.Data.SqlClient.SqlException ex)
{
string msg = "Insert Error:";
msg += ex.Message;
Library.WriteErrorLog(msg);
}
finally
{
conndetail.Close();
}
}
}
FileRecordCount++;
}
sr.Close();
}
catch
{ }
finally
{ }
}
conn.Close();
// Get the unique TischID's and ActualDate from the ActualPlotPreload table. Then loop through each one, adding the ActualUnits
// AcutalDate and TischID to the ActualPlot table. For each unique TischID we make sure that we reset the liTargetUnits to 1 and
// count up as we insert.
SqlCommand cmdGetTischID = new SqlCommand();
SqlDataReader readerTischID;
int liTargetUnits = 0;
string sqlInsert = "INSERT into ActualPlot (ActualUnits, ActualDate, TischID) values (#ActualUnits, #ActualDate, #TischID)";
sql = "SELECT DISTINCT [ActualDate], [TischID] FROM [TaktBoards].[dbo].[ActualPlotPreload] ORDER BY [TischID], [ActualDate] ASC ";
cmdGetTischID.CommandText = sql;
cmdGetTischID.CommandType = CommandType.Text;
cmdGetTischID.Connection = conn;
conn.Open();
readerTischID = cmdGetTischID.ExecuteReader();
DBTischID = "";
DateTime DBActualDate;
string DBTischIDInitial = "";
while (readerTischID.Read())
{
DBTischID = (string)readerTischID["TischID"];
DBActualDate = (DateTime)readerTischID["ActualDate"];
if (DBTischIDInitial != DBTischID)
{
liTargetUnits = 1;
DBTischIDInitial = DBTischID;
}
else
{
liTargetUnits++;
}
try
{
conndetail.Open();
SqlCommand cmd = new SqlCommand(sqlInsert, conndetail);
cmd.Parameters.Add("#ActualUnits", SqlDbType.Real);
cmd.Parameters.Add("#ActualDate", SqlDbType.DateTime);
cmd.Parameters.Add("#TischID", SqlDbType.VarChar);
cmd.Parameters["#TischID"].Value = DBTischID;
cmd.Parameters["#ActualDate"].Value = DBActualDate;
cmd.Parameters["#ActualUnits"].Value = liTargetUnits;
cmd.ExecuteNonQuery();
cmd.Parameters.Clear();
}
catch (System.Data.SqlClient.SqlException ex)
{
string msg = "Insert Error:";
msg += ex.Message;
Library.WriteErrorLog(msg);
}
finally
{
conndetail.Close();
}
}
conn.Close();
Library.WriteErrorLog("SAP text file data has been imported.");
}
If the data is being re-added right back after the delete (basically you know what to re-add before emptying the table), you could have both operation within the same SQL transaction, so that the data will be available to the other page only when it has been re-added.
I mean something like that :
public bool DeleteAndAddData(string connString)
{
using (OleDbConnection conn = new OleDbConnection(connString))
{
OleDbTransaction tran = null;
try
{
conn.Open();
tran = conn.BeginTransaction();
OleDbCommand deleteComm = new OleDbCommand("DELETE FROM Table", conn);
deleteComm.ExecuteNonQuery();
OleDbCommand reAddComm = new OleDbCommand("INSERT INTO Table VALUES(1, 'blabla', 'etc.'", conn);
reAddComm.ExecuteNonQuery();
tran.Commit();
}
catch (Exception ex)
{
tran.Rollback();
return false;
}
}
return true;
}
If your queries don't take too long to execute, you can start the two with a difference of 7.5 seconds, as there is a collision at every 90 seconds when the read/write finishes 3 cycles, and read/view finishes 2 cycles.
That being said, it's not a fool-proof solution, just a trick based on assumptions, in case you wan't to be completely sure that read/view never happens when read/write cycle is happening, try considering having a Read Lock. I would recommend reading Understanding how SQL Server executes a query and Locking in the Database Engine
Hope that helps.
I would try a couple of things:
Make sure your DELETE + INSERT operation is occurring within a single transaction:
BEGIN TRAN
DELETE FROM ...
INSERT INTO ...
COMMIT
If this isn't a busy table, try locking hints your SELECT statement. For example:
SELECT ...
FROM Table
WITH (UPDLOCK, HOLDLOCK)
In the case where the update transactions starts while your SELECT statement is running, this will cause that transaction to wait until the SELECT is finished. Unfortunately it will block other SELECT statements too, but you don't risk reading dirty data.
I was not able to figure this out but I changed my code so the program was not deleting all the rows in the ActualPlot table but checking to see if the row was there and if not adding the new row from the text file.

how to generate unique max id from Data Base

I create a Applicant Registration form where Applicant Registration ID is generated by "Select Max(ID)...." Query. when this query is fetch out the MaxID from Data Base then i increment this ID by Plus one(+1) in this way i generate a Registration ID for all Applicant who register himself. But there is one problem occurred when i run my project from server and multiple clients (Approximately 10) Applicant try to Register then there is "primary key violation exception" occurred. There is 5 Insert Query is executed one-by-one after Max Query is executed
Code is Given Below
public long getUid()
{
try
{
string qry = "select isnull(max(Temp_Applicant_RegNo),0) as appregno FROM Temp_Reg";
if (cs.State == ConnectionState.Closed)
{
cs.Open();
}
cmd = new SqlCommand(qry, cs);
dr = cmd.ExecuteReader();
long cid = 0;
if (dr.Read())
{
cid = long.Parse(dr["appregno"].ToString());
cid++;
}
if (cs.State == ConnectionState.Open)
{
cs.Close();
}
return cid;
}
catch (Exception ex)
{
lbl_ErrorMsg.Text = ex.Message;
return 0;
}
}
protected void Save_btn_Click(object sender, EventArgs e)
{
SqlTransaction trn = null;
try
{
long Regid = getUid();
con.Open();
trn = con.BeginTransaction();
cmd = new SqlCommand("insert into....", con, trn);
cmd.Parameters.AddWithValue("#RegNo", Regid);
cmd.ExecuteNonQuery();
cmd = new SqlCommand("insert into....", con, trn);
cmd.Parameters.AddWithValue("#RegNo", Regid);
cmd.ExecuteNonQuery();
cmd = new SqlCommand("insert into....", con, trn);
cmd.Parameters.AddWithValue("#RegNo", Regid);
cmd.ExecuteNonQuery();
trn.Commit();
}
catch (Exception ex)
{
lbl_ErrorMsg.Text = ex.Message;
trn.Rollback();
}
}
Please give me suggestion that how can i generate Max ID for Applicant so that there is no chance to any duplication. Because i am working in live project.
for there i am using Asp.net C#
Don't do that, let the database generate the key for you when you insert a new row. Here is for example how to do it with SQL Server or MySQL. If you really want to do it on the client, use GUIDs as keys because you can generate them without consulting the database. There are some minor issues with GUIDs as keys because they are usually partially random and this may have negative performance effects on clustered indices, but for 99.9 % of all databases they are just fine.
Solution 1:
You can create a table with only one column, For example "GeneralID", and in your application control this Id to insert in another tables.
Solution 2:
Another solution is create a table and only one column, and a trigger to each table before insert to popule the id getting frmo the "Ids table" to insert.
Before we had auto incrementing columns we would have a table to hold the IDs. It would only have 2 columns IdType varchar(10) and NextId int. Then in a stored proc we would have something like:
while(1=1)
begin
select #nextId = nextId
from MyIds
where IdType=#IdType
update MyIds
set nextId = #nextId + 1
where IdType=#IdType
and nextId = #nextId
if(##ROWCOUNT > 0)
break;
end
select #nextId as nextId
Note that this would only update in the second statement if the nextId didn't change. If it did change it would try again.
I don't see when do you save the new value into Temp_Reg, but how if you save that value immediately after calculation, then you can safety update others tables:
public long getUid()
{
try
{
string qry = "select isnull(max(Temp_Applicant_RegNo),0) as appregno FROM Temp_Reg";
if (cs.State == ConnectionState.Closed)
{
cs.Open();
}
cmd = new SqlCommand(qry, cs);
dr = cmd.ExecuteReader();
long cid = 0;
if (dr.Read())
{
cid = long.Parse(dr["appregno"].ToString());
cid++;
}
UPDATE Temp_reg HERE !!!!
if (cs.State == ConnectionState.Open)
{
cs.Close();
}
return cid;
}
catch (Exception ex)
{
lbl_ErrorMsg.Text = ex.Message;
return 0;
}
}
Then you'll have to take this update into account inside the catch block of Save_btn_Click.
All of this if you can't use Autonumbers but If you can, use it.
If you could change your field Temp_Applicant_RegNo in an IDENTITY column, then you don't need to worry about the next number assigned to your table Temp_Reg. It is all a jopb made by your database.
All you need to know is what number has been assigned and use that number in your subsequent inserts.
This could be easily done using the SELECT SCOPE_IDENTITY() after the insert in your
protected void Save_btn_Click(object sender, EventArgs e)
{
SqlTransaction trn = null;
try
{
con.Open();
trn = con.BeginTransaction();
cmd = new SqlCommand("insert into....; SELECT SCOPE_IDENTITY()", con, trn);
int Regid = Convert.ToInt32(cmd.ExecuteScalar());
cmd = new SqlCommand("insert into....", con, trn);
cmd.Parameters.AddWithValue("#RegNo", Regid);
cmd.ExecuteNonQuery();
cmd = new SqlCommand("insert into....", con, trn);
cmd.Parameters.AddWithValue("#RegNo", Regid);
cmd.ExecuteNonQuery();
trn.Commit();
}
catch (Exception ex)
{
lbl_ErrorMsg.Text = ex.Message;
trn.Rollback();
}
The trick is possible adding the SELECT SCOPE_IDENTITY() as a second query to the first insert and then call ExecuteScalar. ExecuteScalar executes the queries and then returns the value of the first column in the first row of the last query executed.

Checking the number of rows returned from MySQL Data Reader

I am currently working on an C# project and I am trying to get the number of rows returned from MySQL Data Reader.
I know there is no direct function so I am trying to write my own. In the function, I pass it the MySQLDataReader object and then loop through the MySQL Data Reader and increment a counter and return the value of the counter.
This then seems to lock up the program, I guess because I am Reader.read() after I've got the count I'm already at the end. Instead I have tried creating a copy of the reader and then loop through the temp version but I get the same result.
Below is my code where I am executing the query and calling the function.
string query = "SELECT * FROM reports, software, platforms, versions "
+ "WHERE EmailVerified = #verified AND reports.SoftwareID = software.id AND reports.PlatformID = platforms.id "
+ "AND reports.VersionID = versions.id AND BugReportAcceptedNotificationSent = #notificationSent";
using (MySqlCommand cmd = new MySqlCommand(query, db.conn))
{
cmd.Parameters.AddWithValue("#verified", "1");
cmd.Parameters.AddWithValue("#notificationSent", "0");
using (MySqlDataReader reader = cmd.ExecuteReader())
{
totalEmails = HelperClass.totalRowsInMySQLDataReader(reader);
while (reader.Read())
{
currentEmailCount++;
EmailNotifications emailNotification = new EmailNotifications(reader);
emailNotification.sendNewBugReportAfterVerificationEmail(currentEmailCount, totalEmails);
}
}
}
Below is my function that gets the row count
public static int totalRowsInMySQLDataReader(MySqlDataReader reader)
{
MySqlDataReader tempReader = reader;
ILibraryInterface library = GeneralTasks.returnBitsLibrary(Configuration.databaseSettings, Configuration.engineConfig.logFile);
string methodInfo = classDetails + MethodInfo.GetCurrentMethod().Name;
try
{
int count = 0;
while (tempReader.Read())
{
count++;
}
tempReader = null;
return count;
}
catch (Exception ex)
{
string error = string.Format("Failed to get total rows in MySQL Database. Exception: {0}", ex.Message);
library.logging(methodInfo, error);
library.setAlarm(error, CommonTasks.AlarmStatus.Medium, methodInfo);
return -1;
}
}
Make use of a DataTable to load your results, e.g.
DataTable dt = new DataTable();
dt.Load(reader);
int numberOfResults = dt.Rows.Count;
You can then also iterate over the rows to read the values, e.g.
foreach(DataRow dr in dt.Rows)
{
var value = dr["SomeResultingColumn"]
}
The other option is to issue two separate SQL statements, however you would need to ensure both statements were enclosed within a transaction with a Serializable isolation level, this is needed to make sure records aren't inserted between the execution of the two SQL statements.
To avoid multiple queries, how about including the total in the select itself?
SELECT COUNT(*) AS TotalNORows, * FROM reports, software, platforms, versions etc
i think without executing another command it's not possible...as there is no method available for count in reader class
you can try this... if it works..
string query = "SELECT * FROM reports, software, platforms, versions "
+ "WHERE EmailVerified=#verified AND reports.SoftwareID=software.id AND reports.PlatformID=platforms.id "
+ "AND reports.VersionID=versions.id AND BugReportAcceptedNotificationSent=#notificationSent";
using (MySqlCommand cmd = new MySqlCommand(query, db.conn))
{
cmd.Parameters.AddWithValue("#verified", "1");
cmd.Parameters.AddWithValue("#notificationSent", "0");
using (MySqlDataReader reader = cmd.ExecuteReader())
{
// create a new connection db.conn2 then
MySqlCommand cmd2 = new MySqlCommand(query, db.conn2))
cmd2.Parameters.AddWithValue("#verified", "1");
cmd2.Parameters.AddWithValue("#notificationSent", "0");
MySqlDataReader reader2 = cmd2.ExecuteReader();
int numberofrow=0;
while(reader2.Read())
numberofrow++;
//your codes......
}
Was working on the same problem. I hate having to iterate if a method is already available, but this is was the shortest bit I could come up with:
MySqlCommand cmd = new MySqlCommand(query, connection);
MySqlDataReader reader = cmd.ExecuteReader();
int rowcount = 0;
while(reader.Read()){
rowcount++;
}
First, create this class:
public static class Extensions
{
public static int Count(this MySqlDataReader dr)
{
int count = 0;
while(dr.Read())
count++;
return count;
}
}
This will implement .Count () on MySqlDataReader.
int count = reader.Count();
Exemple:
string sql= "SELECT * FROM TABLE";
MySqlCommand cmd = new MySqlCommand(sql, connection);
MySqlDataReader reader = cmd.ExecuteReader();
int count = reader.Count();
Maybe you could look things the other way around
You could just do a select count(*) and get the row count
or
use a data adapter to fill a container (like a DataTable) and count the rows
Unfortunatelly solution from Jan Van #Herck will return one row only, so in case you are interested in getting all rows and their number in one select, this isn't what you need.
In that case I suggest uou to try this:
select * , (select count(*) from my_table) AS numRow from my_table;
or read this:
Getting total mysql results returned from query with a limit: FOUND_ROWS error
You can use follwoing SQL Query to get the total rows Count.
SELECT COUNT(*) FROM [MYTABLE]
from the Code you can use ExecuteScalar() method to get the total number of rows returned by QUERY.
Try This:
int GetRowsCount(MySqlCommand command)
{
int rowsCount=Convert.ToIn32(command.ExecuteScalar());
return rowsCount;
}
Use above function as below:
MySqlCommand command=new MySlCommand("Select count(*) from MyTable",connectionObj);
int totalRows = GetRowsCount(command)
OleDbDataReader dbreader = new OleDbDataReader();
int intcount = 0;
if (dbreader.HasRows == true)
{
if (dbreader.Read())
{
intcount = dbreader.RecordsAffected;
}
}
"dbreader.RecordsAffected" will give you the number rows changed,inserted or deleted by the last statement of SQL

T-SQL Delete * from table then insert into table

Hello I'm trying to do following
Delete all from table X
insert desired values into table X
I thought then T-SQL would be way to achieve that because when something messes up in the INSERT command then everything will be deleted.
But this code does nothing it doesn't insert or delete the data. May someone help me to fix this issue?
spojeni.Open();
SqlTransaction sqlTrans = spojeni.BeginTransaction();
try
{
string delCmdTxt = "TRUNCATE TABLE PLODINY";
SqlCommand cmdDel = spojeni.CreateCommand();
cmdDel.CommandText = delCmdTxt;
cmdDel.Transaction = sqlTrans;
cmdDel.ExecuteNonQuery();
string insert_sql =
"INSERT INTO PLODINY(PLODINA,CENAZAQ,MJ)VALUES(#PLODINA,#CENAZAQ,#MJ)";
SqlCommand sqlcom = spojeni.CreateCommand();
sqlcom.CommandText = insert_sql;
sqlcom.Transaction = sqlTrans;
foreach (DataGridViewRow row in dataGridView1.Rows)
{
sqlcom.Parameters.AddWithValue("#PLODINA", row.Cells["PLODINA"].Value);
sqlcom.Parameters.AddWithValue("#CENAZAQ", row.Cells["CENAZAQ"].Value);
sqlcom.Parameters.AddWithValue("#MJ", row.Cells["MJ"].Value);
sqlcom.ExecuteNonQuery();
sqlcom.Dispose();
}
sqlTrans.Commit();
}
catch (System.Data.SqlClient.SqlException)
{
sqlTrans.Rollback();
}
finally
{
spojeni.Close();
spojeni.Dispose();
}
this.Close();
Your problem is in your foreach loop. You need to define your parameters before hand, and do not dispose the command object until you're all done with it. You can also use the Where extension method to filter out any invalid rows from your data source since its a UI element.
string insert_sql = "INSERT INTO PLODINY(PLODINA,CENAZAQ,MJ)VALUES(#PLODINA,#CENAZAQ,#MJ)";
SqlCommand sqlcom = spojeni.CreateCommand();
sqlcom.CommandText = insert_sql;
sqlcom.Transaction = sqlTrans;
sqlcom.Parameters.Add("#PLODINA");
sqlcom.Parameters.Add("#CENAZAQ");
sqlcom.Parameters.Add("#MJ");
// some validation - add what you need.
var validRows = dataGridView1.Rows.Cast<DataGridViewRow>()
.Where(row => row.Cells["PLODINA"].Value != null);
foreach (DataGridViewRow row in validRows)
{
sqlcom.Parameters[0].Value = row.Cells["PLODINA"].Value;
sqlcom.Parameters[1].Value = row.Cells["CENAZAQ"].Value;
sqlcom.Parameters[2].Value = row.Cells["MJ"].Value;
sqlcom.ExecuteNonQuery();
}
sqlTrans.Commit();
sqlcom.Dispose();
You are doing your parameters totally wrong, because the only thing in your catch is the sqlTrans.Rollback(); you never see the errors you are getting, the first thing I would change is make that catch
catch (System.Data.SqlClient.SqlException)
{
sqlTrans.Rollback();
throw;
}
so you can now see the errors happen.
The next issue is if the table has any foreign key constraints your TRUNCATE TABLE will fail, if it is failing you can simply replace it with
string delCmdTxt = "delete from PLODINY";
SqlCommand cmdDel = spojeni.CreateCommand();
cmdDel.CommandText = delCmdTxt;
cmdDel.Transaction = sqlTrans;
cmdDel.ExecuteNonQuery();
As to why your inserts are not working, you are disposing the command every instance of the for loop, you are also trying to re-add the parameters every time, reformat that loop to the following
string insert_sql = "INSERT INTO PLODINY(PLODINA,CENAZAQ,MJ)VALUES(#PLODINA,#CENAZAQ,#MJ)";
using(SqlCommand sqlcom = spojeni.CreateCommand())
{
sqlcom.CommandText = insert_sql;
sqlcom.Transaction = sqlTrans;
sqlcom.Parameters.Add("#PLODINA", SqlDbType.NVarChar); //Replace with whatever the correct datatypes are
sqlcom.Parameters.Add("#CENAZAQ", SqlDbType.NVarChar);
sqlcom.Parameters.Add("#MJ", SqlDbType.NVarChar);
foreach (DataGridViewRow row in dataGridView1.Rows)
{
sqlcom.Parameters["#PLODINA"] = row.Cells["PLODINA"].Value;
sqlcom.Parameters["#CENAZAQ"] = row.Cells["CENAZAQ"].Value;
sqlcom.Parameters["#MJ"] = row.Cells["MJ"].Value;
sqlcom.ExecuteNonQuery();
}
}
sqlTrans.Commit();
However your code can be made even better, if your DataGridView was backed by a DataTable via binding you could use a SqlTableAdapter instead, Lets say you load the table from the database, display it on the grid, and then you want to push back the updated information. With a DataTable it would be as simple as
private string _getDataQuery = "select PLODINA, CENAZAQ, MJ from PLODINY";
public void GetData(DataTable data)
{
//You do not need to call open here as SqlDataAdapter does it for you internally.
using(var spojeni = new SqlConnection(GetConnectionString())
using(var adapter = new SqlDataAdapter(_getDataQuery, spojeni)
{
data.Clear();
adapter.Fill(data);
}
}
public void UpdateData(DataTable data)
{
using(var spojeni = new SqlConnection(GetConnectionString())
using(var adapter = new SqlDataAdapter(_getDataQuery, spojeni)
using(var commandBuilder = new SqlCommandBuilder(adapter)
{
//This may or may not be nessesary for spojeni.BeginTransaction()
spojeni.Open();
using(var sqlTrans = spojeni.BeginTransaction())
{
adapter.SelectCommand.Transaction = sqlTrans;
adapter.UpdateCommand = commandBuilder.GetUpdateCommand();
adapter.UpdateCommand.Transaction = sqlTrans;
adapter.DeleteCommand = commandBuilder.GetDeleteCommand();
adapter.DeleteCommand.Transaction = sqlTrans;
adapter.InsertCommand = commandBuilder.GetInsertCommand()
adapter.InsertCommand.Transaction = sqlTrans;
try
{
adapter.Update(data);
sqlTrans.Commit();
}
catch
{
sqlTrans.Rollback();
throw;
}
}
}
}
Truncate Table only works if the table has not foreign key constraints... it's probably failing there and then rolling back the transaction in the catch statement...
Instead of Truncate try Delete From table and see if that fixes it...

Categories