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

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.

Related

Is there a way to validate the connection string if the server is closed or down?

I have problem regarding inserting the loop process. So when the connection string determine that the server is down, the inserting process stop looping. My question, is there way to determine whether this connection string is down or not? I have research they answer is to make if condition sqlconn.State == ConnectionState.Open I will show you guys the sample error that I encounter.
string connetionString = null;
MySqlConnection cnn;
connetionString = "server=localhost;database=sample_db_xx;uid=root;pwd=;";
cnn = new MySqlConnection(connetionString);
try
{
var arpp_pro = new List<string>();
cnn.Open();
MySqlCommand command = new MySqlCommand("SELECT store_id,CONCAT(boh,'\\\\sqlexpress') as boh FROM db_cua.stores WHERE " +
"is_active = 1 AND boh != '' ", cnn);
using (MySqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine(reader[0].ToString());
arpp_pro.Add(reader[1].ToString());
}
}
cnn.Close();
foreach (var arpp_pro_data in arpp_pro)
{
string connetionString_SQL = #"Server=" + arpp_pro_data + " \sqlexpress;Database=Site5;User ID=sa;Password=dospos";
//#"Server=" + arpp_pro_data + ";Database=Site5;User ID=sa;Password=dospos";
var date_minus_one_day = DateTime.Today.AddDays(-1);
var formatted_date_minus_one_day = date_minus_one_day.ToString("yyyy-MM-dd");
var year = DateTime.Now.ToString("yyyy");
var month = DateTime.Now.ToString("MM");
var date = DateTime.Today.AddDays(-1);
var date_formatted = date.ToString("dd");
string get_sos_orders_details = #"SELECT
Convert(nvarchar(50),dbo.SOS_ORDERS.OrderId)+ '-'+ Convert(nvarchar(50),dbo.SOS_ORDERS.TransTime) + Convert(nvarchar(50),dbo.Sales.TransactionId)+ Convert(nvarchar(50),dbo.Sales.TotalDeptName) as result,
dbo.Sales.StoreId,
Convert(nvarchar(50),dbo.SOS_ORDERS.TransTime) as TransTime,
dbo.Transactions.OperatorName as Cashier,
dbo.Sales.TotalDeptName as Transaction_Type,
dbo.Sales.TransactionId,
(dbo.SOS_ORDERS.DTOT + dbo.SOS_ORDERS.ASSM) as Cashier_Time,
(dbo.SOS_ORDERS.KIT) as Preparation_Time,
(dbo.SOS_ORDERS.KIT + dbo.SOS_ORDERS.DTOT + dbo.SOS_ORDERS.ASSM) as Total_Time
FROM dbo.SOS_ORDERS INNER JOIN
dbo.Sales ON dbo.SOS_ORDERS.OrderId = dbo.Sales.StoredOrderIndex INNER JOIN
dbo.Transactions ON dbo.Sales.Sequence = dbo.Transactions.Sequence
where dbo.Sales.businessdate= #date_minus_one_day
OR(DATEPART(yy, dbo.SOS_ORDERS.TransTime) = #year
AND DATEPART(mm, dbo.SOS_ORDERS.TransTime) = #month
AND DATEPART(dd, dbo.SOS_ORDERS.TransTime) = #date_today )
AND(dbo.Sales.TotalDeptName in ('01 SALLE MANGER', '02 EMPORTER')
or dbo.Sales.TotalDeptName in ('01 DINE IN', '02 TAKE OUT'))
GROUP BY dbo.SOS_ORDERS.OrderId, dbo.Sales.StoreId, dbo.SOS_ORDERS.TransTime, dbo.SOS_ORDERS.DTOT, dbo.SOS_ORDERS.LINE, dbo.SOS_ORDERS.WIND, dbo.SOS_ORDERS.SERV, dbo.SOS_ORDERS.HOLD,
dbo.SOS_ORDERS.TOTL, dbo.SOS_ORDERS.ASSM, dbo.SOS_ORDERS.CASH, dbo.SOS_ORDERS.FTOT, dbo.SOS_ORDERS.PAY, dbo.SOS_ORDERS.KIT, dbo.Sales.TransactionId,
dbo.Transactions.OperatorName, dbo.Sales.TotalDeptName order by dbo.SOS_ORDERS.TransTime DESC";
using (SqlConnection sqlconn = new SqlConnection(connetionString_SQL))
{
sqlconn.Open();
if (sqlconn.State == ConnectionState.Open)
{
SqlCommand cmd = new SqlCommand(get_sos_orders_details, sqlconn);
cmd.Parameters.AddWithValue("#date_minus_one_day", formatted_date_minus_one_day);
cmd.Parameters.AddWithValue("#year", year);
cmd.Parameters.AddWithValue("#month", month);
cmd.Parameters.AddWithValue("#date_today", date_formatted);
SqlDataReader rs = cmd.ExecuteReader();
while (rs.Read())
{
// access your record colums by using reader
Console.WriteLine(rs["StoreId"]);
cnn.Open();
MySqlCommand comm = cnn.CreateCommand();
comm.CommandText = #"INSERT INTO master_data.so_v2 (StoreId,TransTime,Cashier,Transaction_Type,TransactionId,Cashier_Time,Preparation_Time)
VALUES(#Storeid, #TransTime, #Cashier, #Transaction_Type, #TransactionId, #Cashier_Time, #Preparation_Time)";
comm.Parameters.AddWithValue("#Storeid", rs["StoreId"]);
comm.Parameters.AddWithValue("#TransTime", rs["TransTime"]);
comm.Parameters.AddWithValue("#Cashier", rs["Cashier"]);
comm.Parameters.AddWithValue("#Transaction_Type", rs["Transaction_Type"]);
comm.Parameters.AddWithValue("#TransactionId", rs["TransactionId"]);
comm.Parameters.AddWithValue("#Cashier_Time", rs["Cashier_Time"]);
comm.Parameters.AddWithValue("#Preparation_Time", rs["Preparation_Time"]);
comm.ExecuteNonQuery();
cnn.Close();
}
}
sqlconn.Close();
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
Thank you.
I suppose if all you wanted was a way to test and make sure a connection string is valid and that you can connect to the server and to the database, you could use a method like this:
public bool IsConnectionStringValid(string cs)
{
try
{
using (MySqlConnection conn = new MySqlConnection(cs))
{
conn.Open();
return true;
}
}
catch
{
return false;
}
}
Although I have to admit, in all my years of developing in C#, I've never used anything like this. Normally, as people have said in the comments, you already know before runtime that your connection string is valid and working.

Stop Upload when a some data already exists

I have an upload button that can upload excel file and save it to my database. What I want to happen is that if there's one or more data in that excel file that already existing the other data will also not be uploaded though it's not yet existing. My code for adding it to the database and upload button are below.
Add to database
private void AddNewTrainee(string strdelname, string strrank, string strcomp, string strcourse, string strcenter, string strinst,
string strsdate, string stredate, string strcissued, string strcnumber, string strremark, int recdeleted, string credate, string update, int fromupload)
{
connection.Open();
String checkDateAndName = "Select count(*) from Trainees where StartDate= '" + strsdate + "' and Delegate='" + strdelname + "' and REC_DELETED = 0 ";
SqlCommand cmd = new SqlCommand(checkDateAndName, connection);
int dataRepeated = Convert.ToInt32(cmd.ExecuteScalar().ToString());
bool boolDataRepated;
connection.Close();
if (!(dataRepeated >= 1))
{
boolDataRepated = false;
}
else
boolDataRepated = true;
connection.Open();
string certNumber = "Select * from CertID_Table update CertID_Table set CertificateID = CertificateID + 1 from CertID_Table ";
SqlCommand cmdCert = new SqlCommand(certNumber, connection);
using (SqlDataReader oReader = cmdCert.ExecuteReader())
{
while (oReader.Read())
{
string test1 = oReader["CertificateID"].ToString();
ViewState["certnumber"] = test1;
}
}
connection.Close();
strcnumber = (string)ViewState["certnumber"];
if (boolDataRepated == false)
{
string path = "D:\\Intern\\BASSWeb\\SQLCommands\\AddSQL.txt";
StringBuilder sb = new StringBuilder();
using (StreamReader sr = new StreamReader(path))
{
while (sr.Peek() >= 0)
{
sb.Append(sr.ReadLine());
}
string sql = sb.ToString();
try
{
connection.Open();
SqlCommand cmd1 = new SqlCommand(sql, connection);
cmd1.Parameters.AddWithValue("#delName", strdelname);
cmd1.Parameters.AddWithValue("#rank", strrank);
cmd1.Parameters.AddWithValue("#comp", strcomp);
cmd1.Parameters.AddWithValue("#course", strcourse);
cmd1.Parameters.AddWithValue("#center", strcenter);
cmd1.Parameters.AddWithValue("#instructor", strinst);
cmd1.Parameters.AddWithValue("#sdate", strsdate);
cmd1.Parameters.AddWithValue("#edate", stredate);
cmd1.Parameters.AddWithValue("#cissued", strcissued);
cmd1.Parameters.AddWithValue("#cnumber", strcnumber);
cmd1.Parameters.AddWithValue("#remark", strremark);
cmd1.Parameters.AddWithValue("#rdeleted", recdeleted);
cmd1.Parameters.AddWithValue("#cdate", credate);
cmd1.Parameters.AddWithValue("#udate", update);
cmd1.Parameters.AddWithValue("#fupload", fromupload);
cmd1.CommandType = CommandType.Text;
cmd1.ExecuteNonQuery();
}
catch (System.Data.SqlClient.SqlException ex)
{
string msg = "Insert/Update Error:";
msg += ex.Message;
throw new Exception(msg);
}
finally
{
connection.Close();
}
}
}
else
{
string script = "alert(\"The data already exists\");";
ScriptManager.RegisterStartupScript(this, GetType(), "ServerControlScript", script, true);
}
}
Upload Button
protected void btnUpload_Click(object sender, EventArgs e)
{
if (FileUpload1.HasFile)
{
try
{
string path = Path.GetFileName(FileUpload1.FileName);
path = path.Replace(" ", "");
FileUpload1.SaveAs(Server.MapPath("~/Datas/") + path);
String ExcelPath = Server.MapPath("~/Datas/") + path;
OleDbConnection mycon = new OleDbConnection("Provider = Microsoft.ACE.OLEDB.12.0; Data Source = " + ExcelPath + "; Extended Properties=Excel 8.0; Persist Security Info = False");
mycon.Open();
OleDbCommand cmdX = new OleDbCommand("select * from [Sheet1$]", mycon);
OleDbDataReader dr = cmdX.ExecuteReader();
while (dr.Read())
{
delegateName = dr[0].ToString();
rankPos = dr[1].ToString();
company = dr[2].ToString();
courseTitle = dr[3].ToString();
trainingCenter = dr[4].ToString();
instructor = dr[5].ToString();
staDa = DateTime.Parse(dr[6].ToString());
string startDate = staDa.ToString("MM/dd/yyyy");
endDa = DateTime.Parse(dr[7].ToString());
string endDate = endDa.ToString("MM/dd/yyyy");
certIssued = dr[8].ToString();
certNum = dr[9].ToString();
remarks = dr[10].ToString();
recDeleted = 0;
dateCreated = DateTime.Now.ToString("MM/dd/yyyy HH:mm");
dateUpdated = string.Empty;
fromUpload = 1;
AddNewTrainee(delegateName, rankPos, company, courseTitle, trainingCenter, instructor,
startDate, endDate, certIssued, certNum, remarks, recDeleted, dateCreated, dateUpdated, fromUpload);
}
}
catch (Exception ex)
{
string errorMessage = "alert(\"ERROR: " + ex.Message.ToString() + " \");";
ScriptManager.RegisterStartupScript(this, GetType(), "ServerControlScript", errorMessage, true);
}
}
else
{
string errorMessage = "alert(\"ERROR: You have not specified a file \");";
ScriptManager.RegisterStartupScript(this, GetType(), "ServerControlScript", errorMessage, true);
}
PopulateData();
}
You have to set the transferMode to 'Streamed', otherwise you will always get one file.
Have a look at this article: https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-enable-streaming
I think there is a few things you'll need to tackle to reach your end goal.
Use a multiselect method and a get a post list of all files required
for upload.
Do your processing requirements in a Transaction
When your done processing, commit or rollback the transaction as necessary and keep the data you want.
Study the link I posted a little bit. At first transaction seem a little bit overwhelming, but they are actually very simple. Maybe I can help you get started in your understandings. There are really only three extra steps;
1.
Initialize a transaction object after you create a command.
SqlTransaction transaction = connection.BeginTransaction();
2.
On all of your Sql Commands (Inserts,updates, deletes ect) attach the transaction.
cmd.Transaction = transaction;
This will allow you to Execute the SqlCommands without actually putting them into your database. Lastly, when you've processed all of your inserts and updates you can do the final step. The using statement is not required, just good practice. That could be the next thing you'll want to understand it is very helpful.
3.
Commit all SqlCommands to the database.
transaction.Commit();
If at any point during your data processing, something goes wrong than you can rollback every transaction like this.
transaction.Rollback();

How to get values from table valued function in C#

I have a program where i have to display
The Event Description (OpisDogodka)
Location (Lokacija)
Time (ura)
My table valued function:
[dbo].[DobiDogodek](
#Ime nvarchar(100), #Datum date)
RETURNS TABLE AS RETURN (SELECT OpisDogodka AS 'Opisdogodka',Lokacija, Ura FROM Dogodek WHERE Ime=#Ime AND Datum=#Datum)
My method to connect to the server:
public string Dobi_dogodek(string ime,string datum)
{
string a="";
cmd = new SqlCommand("SELECT * FROM dbo.DobiDogodek(#Ime,#Datum)",povezava); //povezava = connectio and it succeeds to connect to the server.
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("#Ime", ime);
cmd.Parameters.AddWithValue("#Datum", datum); //how to pass date only?
try
{
SqlDataReader Reader = cmd.ExecuteReader();
while(Reader.Read())
{
a = Reader.GetString(0)+" "+Reader.GetString(1)+" "+Reader.GetString(3).ToString(); // get what?
}
Uspeh = true;
}
catch (Exception e)
{
ex = e;
}
finally
{
povezava.Close();
}
return a;
}
I tried also using Datatable and datarow. I am also unsure how to work with Date. I know how to work with DateTime, but I need Date and Time separate. What I am doing wrong?
4.6.2017 (11.40 am CET)Update:
It seems I get the desired result
public List<string> Dobi_dogodek(string ime,string datum)
{
s = new List<string>();
cmd = new SqlCommand("SELECT * FROM dbo.DobiDogodek(#Ime,#Datum)",povezava);
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("#Ime", ime);
cmd.Parameters.AddWithValue("#Datum", Convert.ToDateTime(datum));
dt = new DataTable();
da = new SqlDataAdapter(cmd);
da.Fill(dt);
try
{
foreach (DataRow dr in dt.Rows)
{
s.Add(dr["Opis dogodka"].ToString() + "\\" + dr["Lokacija"].ToString() + "\\" + dr["Ura"].ToString());
}
Uspeh = true;
}
catch (Exception e)
{
ex = e;
}
finally
{
povezava.Close();
}
return s;
}
Now I just need to split the strings according to my requirements, but is the a better (not necessarily an easy) way?
Try this:
cmd.Parameters.AddWithValue("#Datum", Convert.ToDateTime(datum));
See also https://msdn.microsoft.com/en-us/library/cc716729(v=vs.110).aspx .
what is happening when you run it? are you getting an error message? is it getting it as an int? did you see what the sql server is getting from application by using sql profiler?
I will double check but I think your problem is you are not putting quotes around your variables in our statement so when it runs it is evaluating them as ints. try "SELECT * FROM dbo.DobiDogodek('#Ime','#Datum')". It been a long time since I havnt used something like EF...

Efficient Way to Update a lot of Rows from C#

I have a program where I open a SqlConnection, load up a list of objects, modify a value on each object, then update the rows in the SQL Server database. Because the modification requires string parsing I wasn't able to do with with purely T-SQL.
Right now I am looping through the list of objects, and running a SQL update in each iteration. This seems inefficient and I'm wondering if there is a more efficient way to do it using LINQ
The list is called UsageRecords. The value I'm updating is MthlyConsumption.
Here is my code:
foreach (var item in UsageRecords)
{
string UpdateQuery = #"UPDATE tbl810CTImport
SET MthlyConsumption = " + item.MthlyConsumption +
"WHERE ID = " + item.Id;
SqlCommand update = new SqlCommand(UpdateQuery, sourceConnection);
update.ExecuteNonQuery();
}
Try this instead:
string UpdateQuery = #"UPDATE tbl810CTImport SET MthlyConsumption = #consumption WHERE ID = #itemId";
var update = new SqlCommand(UpdateQuery, sourceConnection);
update.Parameters.Add("#consumption", SqlDbType.Int); // Specify the correct types here
update.Parameters.Add("#itemId", SqlDbType.Int); // Specify the correct types here
foreach (var item in UsageRecords)
{
update.Parameters[0].Value = item.MthlyConsumption;
update.Parameters[1].Value = item.Id;
update.ExecuteNonQuery();
}
It should be faster because:
You don't have to create the command each time.
You don't create a new string each time (concatenation)
The query is not parsed at every iteration (Just changes the parameters values).
And it will cache the execution plan. (Thanks to #JohnCarpenter from the comment)
You can either use
SqlDataAdapter - See How to perform batch update in Sql through C# code
or what I have previously done was one of the following:
Tear down the ID's in question, and re-bulkinsert
or
Bulk Insert the ID + new value into a staging table, and update the table on SQL server:
update u
set u.MthlyConsumption = s.MthlyConsumption
from tbl810CTImport u
inner join staging s on
u.id = s.id
In a situation like this, where you can't write a single update statement to cover all your bases, it's a good idea to batch up your statements and run more than one at a time.
var commandSB = new StringBuilder();
int batchCount = 0;
using (var updateCommand = sourceConnection.CreateCommand())
{
foreach (var item in UsageRecords)
{
commandSB.AppendFormat(#"
UPDATE tbl810CTImport
SET MthlyConsumption = #MthlyConsumption{0}
WHERE ID = #ID{0}",
batchCount
);
updateCommand.Parameters.AddWithValue(
"#MthlyConsumption" + batchCount,
item.MthlyConsumption
);
updateCommand.Parameters.AddWithValue(
"#ID" + batchCount,
item.MthlyConsumption
);
if (batchCount == 500) {
updateCommand.CommandText = commandSB.ToString();
updateCommand.ExecuteNonQuery();
commandSB.Clear();
updateCommand.Parameters.Clear();
batchCount = 0;
}
else {
batchCount++;
}
}
if (batchCount != 0) {
updateCommand.ExecuteNonQuery();
}
}
It should be as simple as this . . .
private void button1_Click(object sender, EventArgs e)
{
SqlConnection con = new SqlConnection("Server=YourServerName;Database=YourDataBaseName;Trusted_Connection=True");
try
{
//cmd new SqlCommand( "UPDATE Stocks
//SET Name = #Name, City = #cit Where FirstName = #fn and LastName = #add";
cmd = new SqlCommand("Update Stocks set Ask=#Ask, Bid=#Bid, PreviousClose=#PreviousClose, CurrentOpen=#CurrentOpen Where Name=#Name", con);
cmd.Parameters.AddWithValue("#Name", textBox1.Text);
cmd.Parameters.AddWithValue("#Ask", textBox2.Text);
cmd.Parameters.AddWithValue("#Bid", textBox3.Text);
cmd.Parameters.AddWithValue("#PreviousClose", textBox4.Text);
cmd.Parameters.AddWithValue("#CurrentOpen", textBox5.Text);
con.Open();
int a = cmd.ExecuteNonQuery();
if (a > 0)
{
MessageBox.Show("Data Updated");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
con.Close();
}
}
Change the code to suit your needs.

How to speed up odbc insert

So what I'm doing is reading a lot of data from remote Nettezza database and inserting them into another remote Oracle database. For that I'm using ODBC driver. The problem is that there is a lot of data and it takes too much time. How can I speed up?
Here is what I do:
First I create connection and command for inserting:
String connect = "Driver={Microsoft ODBC for Oracle};CONNECTSTRING=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=myhost)(PORT=myprt))(CONNECT_DATA=(SERVICE_NAME=myname)));Uid=uid;Pwd=pass";
connection = new OdbcConnection(connect);
connection.Open();
String q = #"INSERT INTO TEST (id)
VALUES (?)";
myCommand = new OdbcCommand(q,connection);
Then I read data from netteza:
String connect = "Driver={NetezzaSQL};servername=server;port=5480;database=db; username=user;password=pass;
string query = #"SELECT T2.LETO_MESEC, T1.*
FROM data T1
JOIN datga2 T2 ON T2.ID = T1.EFT_ID
WHERE T2.LETO_MESEC = '" + mesec + #"'";
using (OdbcConnection connection = new OdbcConnection(connect))
{
try
{
OdbcCommand command = new OdbcCommand(query, connection);
connection.Open();
OdbcDataReader reader = command.ExecuteReader();
int counter=0;
while (reader.Read())
{
int id_first = reader.GetInt32(5);
insertOracle(id_first);
}
}
catch (Exception e)
{
Console.WriteLine("ne dela" + e.ToString());
}
}
And finally my insert :
public void insertOracle(int id_first)
{
try
{
myCommand.Parameters.Clear();
myCommand.Parameters.Add(new OdbcParameter("id", id_first));
myCommand.ExecuteNonQuery();
}
catch (Exception e)
{
Console.WriteLine("ne dela" + e.ToString());
}
}
I noticed that these commit in every line, so how to remove that and speed it up. Right now it takes about 10 minutes for 20000 rows.
Single inserts are always going to be slow -- start processing the data in arrays, selecting a batch of ID's from the source system and loading an array to the target.
Here is an article which might be helpful. http://www.oracle.com/technetwork/issue-archive/2009/09-sep/o59odpnet-085168.html

Categories