SQL Select data Delay - c#

I have two application(A & B) and a SQL table (Microsoft SQL Server 2014) with columns as below:
|| Guid || Random || WriteTime || Flag || ReadTime ||
Application A will insert the new row with new Guid, random, WriteTime and Flag.
(Code A)
private void WriteIntoDB(int random)
{
SqlCommand cmd = new SqlCommand();
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
using (SqlTransaction trans = conn.BeginTransaction())
{
SqlCommand command = conn.CreateCommand();
command.Connection = conn;
command.Transaction = trans;
command.CommandText = string.Format("INSERT INTO " + "MyTable" + "([Guid],[Random],[WriteTime],[Flag])" + "VALUES(#Guid,#Random,#WriteTime,#Flag)");
command.Parameters.AddWithValue("#Guid", Guid.NewGuid());
command.Parameters.AddWithValue("#Random", random);
command.Parameters.AddWithValue("#WriteTime", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
command.Parameters.AddWithValue("#Flag", 0);
command.ExecuteNonQuery();
trans.Commit();
}
}
This function will be called six times in TimerA_Tick(with TimerA interval = 1500 millisecond)
And Application B also has a TimerB with interval = 1000 millisecond. In TimerB_Tick, it will select all rows where Flag=0, and change it to 1, also fill in column 'ReadTime'.
(CODE B)
private DataSet DS = new DataSet();
private void ChangeFlag(SqlConnection conn)
{
string cmd = "SELECT * FROM MyTable WHERE Flag = 0";
SqlDataAdapter da = new SqlDataAdapter(cmd, conn);
DS.Tables["test"].Clear();
da.Fill(DS.Tables["test"]);
lock (DS.Tables["test"])
{
using (new SqlCommandBuilder(da))
{
DataRow[] rows = DS.Tables["test"].Select("Flag=0 ", "WriteTime ASC");
foreach (DataRow row in rows)
{
if (Convert.ToInt32(row["Random"]) <= 50)
{
//do something.
}
row["ReadTime"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
row["Flag"] = 1;
da.Update(DS.Tables["test"]);
}
}
}
}
I expect 'Random' which was written in the database first also to be processed by ApplicationB first. Most of the data was, but some of them were not...
The link below is part of that SQL Table, ordered with "WriteTime' ascendant.
There's a row that seems to be processed previously to the data which is written earlier. But I don't know why it happened(and more than one time), also got no idea how to fix it.

Related

Set empty string in TextBox if Database value is null in ASP.Net not working

i have code to read empty row in database, if no row in database then textbox = "0"
my code :
protected void CheckNota()
{
string vNota;
using (SqlConnection con = new SqlConnection(constr))
{
using (SqlCommand cmd1 = new SqlCommand("select ISNULL ((KdNota), 0) as vKdNota from tProdukBeliHead where KdNota = '" + txtKdBeli.Text.Trim() + "'", con))
//using (SqlCommand cmd1 = new SqlCommand("select KdNota from tProdukBeliHead where KdNota = '" + txtKdBeli.Text.Trim() + "'", con))
{
using (SqlDataAdapter da = new SqlDataAdapter(cmd1))
{
DataTable dt = new DataTable();
da.Fill(dt);
if (dt.Rows[0]["vKdNota"] == DBNull.Value)
{
vNota = "0";
}
else
{
vNota = dt.Rows[0]["KdNota"].ToString();
}
}
}
}
}
but textbox not showing value 0, only report this : There is no row at position 0.
thank you
dt.Rows[0] doesn't exist. That would be the first entry in the collection, but the collection is empty. So you are trying to access a row entry to see if it's value is null. Instead you should check if the collection itself is empty. It should look like this
if (dt.Rows.Count == 0)
{
vNota = "0";
}
try this - you don't need a adaptor unless you going to update the results.
Hence:
void CheckNota()
{
string vNota;
using (SqlConnection con = new SqlConnection("your connect string"))
{
using (SqlCommand cmd1 =
new SqlCommand("select ISNULL(KdNota), 0) as vKdNota from tProdukBeliHead where KdNota = #kdNota", con))
{
DataTable dt = new DataTable();
cmd1.Parameters.Add("#kdNota", SqlDbType.NVarChar).Value = txtKdBeli.Text;
con.Open();
dt.Load(cmd1.ExecuteReader());
if (dt.Rows.Count > 0)
vNota = dt.Rows[0]["vKdNota"].ToString();
else
vNota = "0";
}
}
}
as a FYI? We saved some lines of code, so we traded that savings by adding a parameter. This gives us sql injection safe code AND ALSO saved some lines of code. And we also did not have to mess with single quotes in the sql along with concatenation which actually is HARDER to write anyway!

SqlBulkCopy got exception : "Received an invalid column length from the bcp client for colid ."

I have code using SqlBulkCopy to clone a lot of tables, it used to work before, but very weird, recently got exception
Received an invalid column length from the bcp client for colid
I have search this exception and still not solve my problem.
sqlBulkCopy.WriteToServer(reader) will raise this exception if a table has two continous columns which are both of type Char(1) or nvarchar(nn), and both have NULL. Sometime, changing the SqlBulkCopy.BatchSize makes it work, but many times, it will not.
After simplify, I have test case as follow, and it is reproduceable on two servers:
Create a table like below: (tested on SQL Server 2012 SP 4 and SQL Server 2016 SP2)
IF OBJECT_ID('dbo.TestTable', 'U') IS NOT NULL
DROP TABLE dbo.TestTable;
CREATE TABLE [dbo].[TestTable]
(
[value2] [char](1) NULL,
[value1] [char](1) NULL
) ON [PRIMARY]
GO
DECLARE #i int = 0
WHILE #i < 262
BEGIN
SET #i = #i + 1
INSERT INTO [dbo].[TestTable]([value2], [value1])
VALUES (null, null)
END
C# console (.net framework 4.7) code as below
class Program
{
// [change here]
static string sourceConn = #"Server={YourServer};Database={YourDatabase};User ID={userYourName};Password={yourPassword};connect timeout=15";
static void Main(string[] args)
{
CopyTable(sourceConn, sourceConn, "TestTable", "testTableBAK");
Console.ReadLine();
}
static void CopyTable(string sConnSource, string sConnDest, string sTableSource, string sTableDest)
{
if (IsTableExist(sConnDest, sTableDest))
{
RunNonQuerySQL(sConnDest, "DROP TABLE " + sTableDest);
Console.WriteLine($"existing table {sTableDest} dropped");
}
CopySchema(sConnDest, sTableSource, sTableDest);
using (SqlConnection connSource = new SqlConnection(sConnSource))
{
connSource.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = connSource;
cmd.CommandText = "SELECT * FROM " + sTableSource;
// using (SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(sConnDest, SqlBulkCopyOptions.KeepNulls | SqlBulkCopyOptions.KeepIdentity))
using (SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(sConnDest))
{
// sqlBulkCopy.BatchSize = 1380; // this optional setting will work if set value smaller than 1397 for testTable on my new server (SQL server 13.0.5102.14)
// sqlBulkCopy.BatchSize = 261; // this optional setting will work if set value smaller than 261 for testTable on 2 older server (SQL server 11.0.7001)
sqlBulkCopy.DestinationTableName = sTableDest;
SqlDataReader reader = cmd.ExecuteReader();
try
{
// exception here
sqlBulkCopy.WriteToServer(reader);
Console.WriteLine("table copied");
}
catch (SqlException ex)
{
Console.WriteLine(ex.Message);
}
sqlBulkCopy.Close();
}
}
}
static bool IsTableExist(string sConn, string sTableName)
{
bool result = false;
using (SqlConnection conn = new SqlConnection(sConn))
{
conn.Open();
SqlCommand cmd = new SqlCommand();
string[] s = sTableName.Split('.');
if (s.Length > 1)
{
cmd.CommandText = "select count (*) as counter from information_schema.tables where table_name = '" + s[1] + "' and TABLE_SCHEMA='" + s[0] + "'";
}
else
{
cmd.CommandText = "select count (*) as counter from information_schema.tables where table_name = '" + sTableName + "'";
}
cmd.Connection = conn;
var count = Convert.ToInt32(cmd.ExecuteScalar());
result = count > 0;
}
return result;
}
static bool RunNonQuerySQL(string sConn, string sSQL)
{
bool result = false;
using (SqlConnection conn = new SqlConnection(sConn))
{
conn.Open();
SqlCommand cmd = new SqlCommand();
cmd.CommandText = sSQL;
cmd.Connection = conn;
var count = cmd.ExecuteNonQuery();
result = true;
}
return result;
}
static public bool CopySchema(string sConn, string sTableSource, string sTableDest)
{
return RunQuerySQL(sConn, "select * into " + sTableDest + " from " + sTableSource + " where 1=2");
}
static public bool RunQuerySQL(string sConn, string sSQL)
{
using (SqlConnection conn = new SqlConnection(sConn))
{
conn.Open();
SqlCommand cmd = new SqlCommand();
cmd.CommandText = sSQL;
cmd.Connection = conn;
SqlDataReader reader = cmd.ExecuteReader();
if (reader.Read())
{
return true;
}
else
{
return false;
}
}
}
}
I just experienced this error.
I tried to insert a string with a lenght of 5 into a table column with a definition of "varchar(4)".
The error message in my case was:
"Received an invalid column length from the bcp client for colid 2".
"Colid 2" refered to the second column of the row (DataRow) that was part of the DataTable which I used as parameter for the call to the SqlBulkCopy.WriteToServer(DataTable table) method.
The solution in my case was to add validation code that checks the lenght of the strings in my input data before trying to call SqlBulkCopy.WriteToServer().

Integer is being returned as 0 when it shouldn't be. Retrieved from database

I'm trying to get a value from my database but it keeps returning a value of 0 and i cannot figure out why. I've been retrieving data from the database for the whole of my project and it is just not working here. None of the values in the database are = to 0.
int rentalPrice is the one being returned as 0`
protected void Page_Load(object sender, EventArgs e)
{
if (Request.QueryString["id"] == null)
{
Response.Redirect("DisplayCars.aspx");
}
else
{
id = Convert.ToInt32(Request.QueryString["id"].ToString());
con.Open();
SqlCommand cmd = con.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = "select * from cars where id ='" + id + "'";
cmd.ExecuteNonQuery();
lblCarID.Text = id.ToString();
DataTable dt2 = new DataTable();
SqlDataAdapter da2 = new SqlDataAdapter(cmd);
foreach (DataRow dr2 in dt2.Rows)
{
rentalPrice = Convert.ToInt32(dr2["car_rental_price"]);
}
lblRentalPrice.Text = rentalPrice.ToString();
con.Close();
}
// This uses a Connection pool, so you don't need to reuse the same SqlConnection
using (SqlConnection con = new SqlConnection(...))
{
using (SqlCommand cmd = con.CreateCommand())
{
cmd.CommandType = CommandType.Text;
cmd.CommandText = "select [car_rental_price] from cars where id = #Id";
var idParam = new SqlParameter("#Id");
idParam.Value = id;
cmd.Parameters.Add(idParam);
con.Open();
using (var reader = cmd.ExcecuteReader())
{
reader.Read();
lblRentalPrice.Text = reader.GetInt32(0).ToString();
lblCarID.Text = id.ToString();}
}
}
}
To execute a query and get results, you need to use cmd.ExecuteReader.
Also, rather than concatenating values into a string to build your SQL query, you need to use parameterized queries. This helps prevent SQL Injection attacks.
Also, SqlConnection should not be put in a field (class level variable). Instead, you should use local variables and wrap them in a using statement to ensure that they get disposed of properly.
hey you did not fill the Data Table.. then how it has any Values???
first Fill the data Table and use it in Foreach loop
adapter.Fill(DataTable);
foreach(DataRow dr in DataTable)
{
//get the id
}

How to insert date time in database?

I'am making a time attendance system and I don't know how to store datetime in database. I really need some help with my system if anyone has any code for time attendance please share your Code a little help would do thanks..
Here is my Code:
con = newSqlConnection(#"DataSource=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\Database.mdf;Integrated Security=True;User Instance=True");
dt = new DataTable();
cmd = new SqlCommand(#"SELECT EmpID FROM data WHERE EmpID='" + Code.Text + "'", con);
con.Open();
sdr = cmd.ExecuteReader();
int count = 0;
while (sdr.Read())
{
count = count + 1;
}
con.Close();
if (count == 1)
{
con.Open();
DateTime dtn = DateTime.Now;
dtn = Convert.ToDateTime(DateTime.Now.ToString("hh:mm"));
string query = #"INSERT INTO Time (TimeIn) Values ('" + dtn + "')";
cmdd = new SqlCommand(query, con);
sdr = cmdd.ExecuteReader();
sdr.Read();
dataGridView.DataSource = databaseDataSet.Time ;
con.Close();
MessageBox.Show("Verify Ok");
}
else
{
MessageBox.Show("Please Try Again");
}
Do not use ExecuteReader() but ExecuteNonQuery(); add query parameters, do not modify query text, technically it could be something like that:
...
if (count == 1) {
...
DateTime dtn = DateTime.Now;
string query =
#"insert into Time (
TimeIn)
values (
#TimeIn)"; // <- query parameter instead of query text modification
using (var query = new SqlCommand(query, con)) {
// bind query parameter with its actual value
query.Parameters.AddWithValue("#TimeIn", dtn);
// Just execute query, no reader
query.ExecuteNonQuery();
}
...
However, table Time as it appears in the question looks very strange, hardly does it contain TimeIn field only.

Increase performance on OleDB insert into statement, BeginTransaction CommitTransaction

I have written to append functions that insert data from custom c# list into MSAccess.
The first simply sets up a new connection for each individual recordset:
public static void appenddatatotable(string connectionstring, string tablename, string[] values)
{
var myconn = new OleDbConnection(connectionstring);
var cmd = new OleDbCommand();
cmd.CommandText = "INSERT INTO " + tablename + " ([RunDate],[ReportingGroup], [Tariff], [Year]) VALUES(#RunDate, #ReportingGroup, #Tariff, #Year)";
cmd.Parameters.AddRange(new[] { new OleDbParameter("#RunDate", values[0]), new OleDbParameter("#ReportingGroup", values[1]), new OleDbParameter("#Tariff", values[2]), new OleDbParameter("#Year", values[3])});
cmd.Connection = myconn;
myconn.Open();
cmd.ExecuteNonQuery();
myconn.Close();
}
I then simply loop over my list of values and call this function on each iteration. This works fine but is slow.
In the second function I tried to include the loop in the function and work with BeginTransction and Committransaction:
public static void appenddatatotable2(string connectionstring, string tablename, string datstr, List<PowRes> values)
{
var myconn = new OleDbConnection(connectionstring);
int icounter = 0;
var cmd = new OleDbCommand();
OleDbTransaction trans = null;
cmd.Connection = myconn;
myconn.Open();
foreach (var item in values)
{
if (icounter == 0)
{
trans = cmd.Connection.BeginTransaction();
cmd.Transaction = trans;
}
cmd.CommandText = "INSERT INTO " + tablename + " ([RunDate],[ReportingGroup], [Tariff], [Year]) VALUES(#RunDate, #ReportingGroup, #Tariff, #Year)";
if (string.IsNullOrEmpty(item.yr))
item.yr = "";
cmd.Parameters.AddRange(new[] { new OleDbParameter("#RunDate", datstr), new OleDbParameter("#ReportingGroup", item.RG), new OleDbParameter("#Tariff", item.tar), new OleDbParameter("#Year", item.yr)});
cmd.ExecuteNonQuery();
icounter++;
if (icounter >= 500)
{
trans.Commit();
icounter = 0;
}
}
if (icounter > 0)
{
trans.Commit();
}
myconn.Close();
}
This also works fine but is EVEN slower.
Is my code wrong? How could I speed up the multiple inserts?
Thanks!
did not test, just my guess for your second function: you add too many parameters to the same command over the loop - cmd.Parameters were never cleared before each usage..
normally committing large set of commands within one connection is much faster than doing them one by one at single connection.
another way to speed up your inserts is to dump all your insert statements into a long text, separated with semicolon, and then fire a commit in one go (i am not sure whether msAccess supports it or not)
EDIT:
to combine the update command into one text:
var updates = values.Select(x => string.Format("INSERT INTO myTable ([RunDate],[ReportingGroup], [Tariff], [Year]) VALUES({0}, {1}, {2}, {3})",
datstr, x.RG, x.tar, x.yr))
.Aggregate((m, n) => m + ";" + n);
cmd.CommandText = update;
Though this could have sql injection issues.
this should be significantly faster than all of your exiting versions
public static void appenddatatotable2(string connectionstring, string tablename, string datstr, List<PowRes> values)
{
string commandText = "INSERT INTO " + tablename + " ([RunDate],[ReportingGroup], [Tariff], [Year]) VALUES(#RunDate, #ReportingGroup, #Tariff, #Year)";
using (var myconn = new OleDbConnection(connectionstring))
{
myconn.Open();
using (var cmd = new OleDbCommand())
{
foreach (var item in values)
{
cmd.CommandText = commandText;
cmd.Parameters.Clear();
cmd.Parameters.AddRange(new[] { new OleDbParameter("#RunDate", datstr), new OleDbParameter("#ReportingGroup", item.RG), new OleDbParameter("#Tariff", item.tar), new OleDbParameter("#Year", item.yr) });
cmd.Connection = myconn;
cmd.Prepare();
cmd.ExecuteNonQuery();
}
}
}
}

Categories