I've a problem with SqlConnection in C#. I do a large number of INSERT NonQuery, but in any case SqlConnection save in the database always the first 573 rows. This is the method I use for queries. In this method there is a lock because I use different thread to save the data.
public void InsertElement(string link, string titolo, string text)
{
string conString = "*****************";
using (SqlConnection connection = new SqlConnection(conString))
{
connection.Open();
text = text.Replace("\"", "");
DateTime localDate = DateTime.Now;
lock (thisLock)
{
string query = "IF (NOT EXISTS(SELECT * FROM Result " +
" WHERE Link = '" + link + "')) " +
" BEGIN " +
" INSERT INTO Result ([Titolo],[Link],[Descrizione],[DataRicerca],[FKDatiRicercheID]) " +
" VALUES('" + titolo + "', '" + link + "', '" + text + "', '" + localDate + "', 1) " +
" END";
if (connection != null)
{
SqlCommand cmd = new SqlCommand(query, connection);
cmd.ExecuteNonQuery();
}
}
}
}
This is the code of the loop that call the method InsertElement()
public void Save()
{
string[] DatiLetti;
string url = "";
while (result.Count > 0)
{
try
{
url = result.Last();
result.RemoveAt(result.Count - 1);
DatiLetti = ex.DirectExtractText(url);
if (DatiLetti[0].Length > 2)
{
ssc.InsertGare(url, DatiLetti[0], DatiLetti[1]);
}
}
catch (Exception exc)
{
logger.Error("Exception SpiderSave> " + exc);
}
}
}
Result is a volatile array that is progressively filled from other thread. I'm sure that the array contains more than 573 items.
I try to search one solution, but all the answers say that the number of database connections for SQLServer is over 32K at a time and I've already checked this number in my database. Is there anyone who can help me understand the problem?
Don't open a connection for every insert. Use one connection, then pass that connection through to your insert, like this :
public void InsertElement(string link, string titolo, string text, SqlConnection conn)
{
text = text.Replace("\"", "");
DateTime localDate = DateTime.Now;
lock (thisLock)
{
string query = "IF (NOT EXISTS(SELECT * FROM Result " +
" WHERE Link = '" + link + "')) " +
" BEGIN " +
" INSERT INTO Result ([Titolo],[Link],[Descrizione],[DataRicerca],[FKDatiRicercheID]) " +
" VALUES('" + titolo + "', '" + link + "', '" + text + "', '" + localDate + "', 1) " +
" END";
if (connection != null)
{
SqlCommand cmd = new SqlCommand(query, connection);
cmd.ExecuteNonQuery();
}
}
}
I recommend also looking at paramatizing your query, as well as using bulk inserts, and not individual inserts
If you are executing InsertElement() once for each rows of data to insert, then the execution will be too slow for large no. of rows. (Also, you are creating SqlConnection for each query execution.) Try adding many rows at once using a single INSERT query:
INSERT INTO tablename
(c1,c2,c3)
VALUES
(v1,v2,v3),
(v4,v5,v6)
...
Related
I am trying to read an integer from a SQL Server database by text in comboboxes.
I get a "Syntax error" "near" my Table name "Seeweg". The debugger does not highlight the line, where the error happens.
The column with the value I like to get is named seadistance. The other columns, by which to sort are start and ziel.
They get sorted by the values written in the comboboxes.
To reproduce this procedure I inserted the code into a class and called the instance by a button named btnSea.
I already searched for similar problems, but I could not find any syntax errors concerning the string implementation. The column names are correct.
//The Button
private void btnSea_Click(object sender, EventArgs e)
{
Entnehmen CO2 = new Entnehmen();
int Dist = CO2.Werte("Seeweg", "start", "ziel", "seadistance", comboSeaOrig.Text, comboSeaDest.Text);
MessageBox.Show(Dist.ToString());
}
//The class
class Entnehmen
{
public int Werte(string Tabelle, string Reihe1, string Reihe2, string Wertereihe, string WertReihe1, string WertReihe2)
{
int Wert = 0;
string myConnection = #"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\Database1.mdf;Integrated Security=True;Connect Timeout=30";
using (SqlConnection myConn = new SqlConnection(myConnection))
{
myConn.Open();
SqlCommand SelectCommand = new SqlCommand("SELECT '" + Wertereihe + "' FROM '" + Tabelle + "' WHERE '" + Reihe1 + "' = '" + WertReihe1 + "' AND '" + Reihe2 + "' = '" + WertReihe2 + "' ; ", myConn);
Wert = (int)SelectCommand.ExecuteScalar();
}
return Wert;
}
}
}
I expect the value to be given back. Before that happens, I get the error:
Incorrect syntex near 'Seeweg'
Where is the syntax mistake? Any help is appreciated =)
You are generating something like:
SELECT 'seadistance' FROM 'Seeweg' WHERE 'start' = 'aa' AND 'ziel' = 'bbb'
This is not a valid T-SQL statement. Correct your quotes in columns and tables variables.
This is a suggestion of how you can write your T-SQL statemant based on your code:
SqlCommand SelectCommand = new SqlCommand("SELECT " + Wertereihe + " FROM " + Tabelle + " WHERE " + Reihe1 + " = '" + WertReihe1 + "' AND " + Reihe2 + " = '" + WertReihe2 + "' ; ", myConn);
i'm trying to lock the table som other client can't change in it until i'm done but its not working. i have create 2 projekt, both is exactly the same. i start those project at a same time. when i chose the table it should lock that table but the other projekt still can get the table and make change. here is the code i have done.
SqlConnection con = new SqlConnection(ConStr);
con.Open();
SqlCommand _Command = new SqlCommand("SELECT * FROM " + table + " WITH (TABLOCK,HOLDLOCK)", con);
_Command.CommandType = CommandType.Text;
_Command = con.CreateCommand();
SqlTransaction _Transaction = con.BeginTransaction(IsolationLevel.Serializable);
_Command.Connection = con;
_Command.Transaction = _Transaction ;
public void Commit()
{
_Command.CommandText = "UPDATE " + table + " SET " + column[1] + " = '" +
txtBox1.Text + "', " + column[2] + " = '" +
txtBox2.Text + "', " + column[3] + " = '" +
txtBox3.Text + "', " + column[4] + " = '" +
txtBox4.Text + "' WHERE " + column[0] + " = " + txtBox0.Text;
_Command.ExecuteNonQuery();
if (_Transaction != null)
{
_Transaction .Commit();
}
}
public void commit is for later on when i'm done with the change.
thanks in advance
This is the modern syntax for what you're attempting. Also, according to the documentation, you shouldn't require table hints with IsolationLevel.Serializable. To maintain your lock, you need to create your transaction before selecting from the first query.
When using TransactionScopes, the framework will automatically enroll connections in open transactions and automatically rollback if scope.Complete() hasn't been called. I.e. An error occurred or you skipped scope.Complete() because of some failed verification.
https://msdn.microsoft.com/en-us/library/system.data.isolationlevel%28v=vs.110%29.aspx
var options = new TransactionOptions();
options.IsolationLevel = IsolationLevel.Serializable;
using (var scope = new TransactionScope(TransactionScopeOption.Required, options))
{
var something = ReadSomething();
WriteSomething(something);
scope.Complete();
}
Try use TABLOCKX :
SELECT * FROM table (TABLOCKX)
The above command will queue other reads and updates outside your transaction until the transaction commite or rolled back
I wanted to update the values of a few columns of a database table, using queries or stored procedure, but wanted to use my C# library to alter the value.
For eg, I want the columns A,B,C of table T to be replaced with Encrypt(A), Encrypt(B) and Encrypt(C) where Encrypt is a part of a C# library. I could have done it in a simple console application, but I have to do this process for a lot of columns in lot of tables.
Could I use a SQLCLR stored procedure / query to do this process in SQL Server Management Studio? It will be really great if someone could assist in this.
public class SP
{
[Microsoft.SqlServer.Server.SqlFunction()]
public static void Enc()
{
using (SqlConnection connection = new SqlConnection("context connection=true"))
{
connection.Open();
SqlCommand command;
SqlCommand command1;
for (int i = 0; i < 1; i++)
{
command = new SqlCommand("SELECT " + tableFieldArray[i, 1].ToString() + " FROM " + tableFieldArray[i, 0].ToString(), connection);
SqlDataReader reader = command.ExecuteReader();
using (reader)
{
while (reader.Read())
{
if (!reader.IsDBNull(0) && !String.IsNullOrEmpty(reader.GetString(0)))
{
//SqlContext.Pipe.Send("Data = " + reader.GetString(0) + "; Encrypted = " + Encrypt(reader.GetString(0)));
SqlContext.Pipe.Send("UPDATE " + tableFieldArray[i, 0].ToString() + " SET "
+ tableFieldArray[i, 1].ToString() + " = '" + Encrypt(reader.GetString(0)) + "' "
+ "WHERE " + tableFieldArray[i, 1].ToString() + " = '" + reader.GetString(0) + "'");
//query = "UPDATE " + tableFieldArray[i, 0].ToString() + " SET "
// + tableFieldArray[i, 1].ToString() + " = '" + Encrypt(reader.GetString(0)) + "' "
// + "WHERE " + tableFieldArray[i, 1].ToString() + " = '" + reader.GetString(0) + "'";
command1 = new SqlCommand("UPDATE " + tableFieldArray[i, 0].ToString() + " SET "
+ tableFieldArray[i, 1].ToString() + " = '" + Encrypt(reader.GetString(0)) + "' "
+ "WHERE " + tableFieldArray[i, 1].ToString() + " = '" + reader.GetString(0) + "'",connection);
}
}
}
SqlCommand command1 = new SqlCommand(query , connection);
command1.ExecuteNonQuery();
}
connection.Close();
}
}
public static string Encrypt(string TextFromForm)
{
//implementation
}
}
}
You can use SQLCLR to call encryption from C#, though this is the wrong approach. If you need to do a custom algorithm, you should encapsulate that into a SQLCLR function so that it can be used in an UPDATE statement or even an INSERT or SELECT or anywhere. Something like:
public class SP
{
[Microsoft.SqlServer.Server.SqlFunction(IsDeterministic = true)]
public static SqlString EncryptByAES(SqlString TextToEncrypt)
{
return DoSomething(TextToEncrypt.Value);
}
}
Then you can use that function as follows:
UPDATE tb
SET tb.FieldA = EncryptByAES(tb.FieldA)
FROM dbo.TableName tb
WHERE tb.FieldA some_test_to_determine_that_FieldA_is_not_alreay_encrypted;
BUT, before you write a custom encryption algorithm, you might want to check out the several built-in paired ENCRYPTBY / DECRYPTBY functions that might do exactly what you need:
ENCRYPTBYASYMKEY / DECRYPTBYASYMKEY
ENCRYPTBYCERT / DECRYPTBYCERT
ENCRYPTBYKEY / DECRYPTBYKEY
ENCRYPTBYPASSPHRASE / DECRYPTBYPASSPHRASE
The current program I am building is used to save invoices and I want to save data into a database. However instead of repeating this code shown below 20 times for each possible entry i would like to create a function with the text box name changing in the function.
All the text boxes are named with a number at the end from 1 to 20. I was wondering if there is a way to have a function that would change the number at the end and if its even worth doing compared to repeating this 20 times.
if (txtProductID1.Text.Length > 0)
{
OleDbConnection oledbconnection1 = new OleDbConnection();
oledbconnection1.ConnectionString = Con;
OleDbCommand cmd;
String strInsert = "";
//Generate SQL Statement
strInsert = "Insert into [InvoiceOrder] Values (";
strInsert += "'1', ";
strInsert += "'" + txtInvoiceNo.Text + "', ";
strInsert += "'" + txtProductDescription1.Text + "', ";
strInsert += "'" + txtOrderNo1.Text + "', ";
strInsert += "'" + cboUnit1.Text + "', ";
strInsert += "'" + txtAmount1.Text + "', ";
strInsert += "'" + txtPrice1.Text + "', ";
strInsert += "'" + txtSum1.Text + "', ";
strInsert += "'" + txtDiscount1.Text + "' ";
strInsert += ")";
try
{
oledbconnection1.Open();
cmd = new OleDbCommand();
cmd.CommandText = strInsert;
cmd.Connection = oledbconnection1;
cmd.ExecuteNonQuery();
//MessageBox.Show("Record saved");
}
catch (Exception ex)
{
MessageBox.Show("Error : " + ex.ToString());
}
finally
{
oledbconnection1.Close();
}
}
First, parameterize your query. Aside from security, the query you're building up is going to trip you up when you forget a single apostrophe somewhere.
As for iterating through the controls, perhaps Controls.Find() will work for you. The following code assumes all controls have a number from 1 to 20, and each number occurs once and only once on the form. (In your example, txtInvoiceNo does not have a number - I assume that's a typo.)
I made a few other changes too, like replacing your finally block with a using block, which will close and dispose your connection for you.
for (var i = 1; i <= 20; i++)
{
if (!String.IsNullOrEmpty(Controls.Find("txtProductID" + i, true).Single().Text))
{
using (var oledbconnection1 = new OleDbConnection())
{
oledbconnection1.ConnectionString = Con;
oledbconnection1.Open();
var insertStatement =
"Insert into [InvoiceOrder] Values ('1', #InvoiceNo, #ProductDesc, #OrderNo, #Unit, #Amount, #Price, #Sum, #Discount)";
try
{
using (var cmd = new OleDbCommand(insertStatement, oledbconnection1))
{
cmd.Parameters.AddWithValue("#InvoiceNo", Controls.Find("txtInvoiceNo" + i, true).Single().Text);
...
...
cmd.Parameters.AddWithValue("#Discount", Controls.Find("txtDiscount" + i, true).Single().Text);
cmd.ExecuteNonQuery();
//MessageBox.Show("Record saved");
}
}
catch (Exception ex)
{
MessageBox.Show("Error : " + ex.ToString());
}
}
}
}
I am getting an error while i am trying to insert a user id of my client in the ms access database.
The error i am getting is Overflow.
when i am trying to insert its getting the above error.
I am using these code.
OleDbCommand cmd = new OleDbCommand("insert into UserInfo " + "([firstname], [lastname], [gender], [occupation], [expirydate], [UserId], [phoneno]) " + " values('" + txt_FirstName.Text + "','" + txt_LastName.Text + "','" + cmb_Gender.Text + "','" + cmb_Occupation.Text + "','" + txt_expiryDate.Text + "','" + txt_HardDiskId.Text + "','" + txt_PhoneNo.Text + "');", con);
OleDbCommand cmd1 = new OleDbCommand("select * from UserInfo where (HardDiskId='" + txt_HardDiskId.Text + "')", con);
int temp = 0;
try
{
con.Open();
string count = (string)cmd1.ExecuteScalar();
if ((count == "") || (count == null))
{
temp = cmd.ExecuteNonQuery();
if (temp > 0)
{
MessageBox.Show("User ID of " + txt_FirstName.Text + " " + txt_LastName.Text + " has been added");
}
else
{
MessageBox.Show("Record not added");
}
}
else
{
MessageBox.Show("User ID of " + txt_FirstName.Text + " already exists. Try another user ID.");
}
}
Aside from being open to SQL Injection (which you should parameterize your OleDbCommand), first thought on a problem is what you are trying to store the data. Do any of the text fields have special characters or apostrophe in name which would otherwise pre-terminate your embedded .... '" + nextField + "' ..." entries and throw the balance off.
Another... don't know if the parser is picky or not... but a space after values, before open paren.... " values(" to " values (".
Third, and more probable the issue is the expiration date. If its a date field, and you are trying to put in as text, it might be failing on the data type conversion.