In this code every time ShenasehSamapel is two equal values I get an exception that says field ShenasehSamapel is not the primary key:
"The variable name '#ShenasehSamapel' has already been declared.
Variable names must be unique within a query batch or stored
procedure."
Here is the code that generates the error:
private void btnDefineNewKala_Click(object sender, EventArgs e)
{
if (txtShenasehSamapel.Text != "" & txtKalaName.Text != "")
{
//Anbar.FildArray[0]= txtRadif.Text;
Anbar.FildArray [1]= txtShenasehSamapel.Text;
Anbar.FildArray[2] =txtKalaName.Text;
string strDefineKala = "insert into AnbarFava.dbo.DefineKala (ShenasehSamapel ,KalaName )" +
" values ( #ShenasehSamapel , #KalaName )";
//Anbar.AnbarCMD.Parameters.AddWithValue("#Radif", Anbar.FildArray[0]);
Anbar.AnbarCMD.Parameters.AddWithValue("#ShenasehSamapel", Anbar.FildArray[1]);
Anbar.AnbarCMD.Parameters.AddWithValue("#KalaName", Anbar.FildArray[2]);
Anbar.RunQuery(strDefineKala);
for (int Element = 0; Element <= Anbar.FildArray.Length - 1; Element++)
{ Anbar.FildArray[Element] = null; }
//txtRadif.Text = " ";
txtShenasehSamapel.Text = "";
txtKalaName.Text = "";
/**/
string strcmd = "select * from AnbarFava.dbo.DefineKala";
SqlDataAdapter thisDataAdapter = new SqlDataAdapter(strcmd, Anbar.strCNN);
DataTable thisDataTable = new DataTable();
thisDataAdapter.Fill(thisDataTable);
dgvDefineKala.DataSource = thisDataTable;
}
else
{
MessageBox.Show("لطفا تمام خانه ها را پر کنید", "خطا",
MessageBoxButtons.OK); }
}
You are reusing connections and commands across function calls, you have a parameter from a previous call conflicting with your current call.
Anbar.AnbarCMD should not exist, you should create a new command each time. I also assume Anbar also holds a SqlConnection object, it should not be doing that either. All Anbar should hold is a connection string and a new connection and new command should be created each Click (Be sure to put the command and connection inside using statements so they get disposed)
I don't know exactly what RunQuery is doing but it could be rewritten to something similar to
public void RunQuery(string query, params SqlParameter[] parameters)
{
using(var connection = new SqlConnection(_connectionString)
using(var command = new SqlQuery(query, connection)
{
connection.Open();
command.Parameters.AddRange(parameters);
command.ExecuteNonQuery();
}
}
You then call it like so
var param1 = new SqlParameter("#ShenasehSamapel", Anbar.FildArray[1]);
var param2 = new SqlParameter("#KalaName", Anbar.FildArray[2]);
Anbar.RunQuery(strDefineKala, param1, param2);
Related
I'm working with a local database in a Windows Form Application. It works like charm, but I wanted to check if a record that a user searchs for is in the dataBase. I wrote the following code, but I get an error and I can't figure out how to solve it. I know that I reference a non-static object to a static method. But didn't know how to solve it. Thank in advance !
private void button1_Click(object sender, EventArgs e)
{
if (textBox1.Text.Length != 0)
{
var connString = #"Data Source=C:\Users\Andrei\Documents\Visual Studio 2010\Projects\Stellwag\Stellwag\Angajati.sdf";
using (var conn = new SqlCeConnection(connString))
{
try
{
var numePrenume = textBox1.Text.Trim().Split(' ');
var nume = numePrenume[0];
var prenume = numePrenume[1];
conn.Open();
var query = "SELECT COUNT(*) FROM info WHERE Nume='" + nume + "' AND Prenume='" + prenume + "'";
var command = new SqlCeCommand(query, conn);
var dataAdapter = new SqlCeDataAdapter(command);
var dataTable = new DataTable();
dataAdapter.Fill(dataTable);
int userCount = (int) SqlCeCommand.ExecuteScalar();
if (userCount > 0)
{
Info form = new Info(nume, prenume);
form.Show();
}
else
{
MessageBox.Show("Nu exista un angajat cu acest nume");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
}
Replace int userCount = (int) SqlCeCommand.ExecuteScalar(); with
int userCount = (int) command.ExecuteScalar();
because SqlCeCommand is a class and ExecuteScalar() is a non-static method of that class. so you cannot access ExecuteScalar() without a reference. in this statement var command = new SqlCeCommand(query, conn); you are creating a reference to that class so you can call ExecuteScalar() through this reference.
You need to use your SqlCeCommand object, not the class itself. Just change your
int userCount = (int)SqlCeCommand.ExecuteScalar();
to
int userCount = (int)command.ExecuteScalar();
A few things more;
You have an extra * after your COUNT(*). Remove it.
You should always use parameterized queries. This kind of string concatenations are open for SQL Injection attacks.
Use using statement to dispose your command and adapter automatically as you did for your connection.
I have a gridview and I want to checked line in insert but I see this error:
CommandText property has not been initialized.
I guess my mistake about strArrays. I'm working two days about it
How can I fixed?
StringBuilder stringBuilder = new StringBuilder(string.Empty);
SqlConnection sqlConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["SiteSqlServer"].ConnectionString.ToString());
SqlCommand sqlCommand = new SqlCommand();
for (int i = 0; i < GridView1.Rows.Count; i++)
{
int type = 2;
CheckBox chkUpdate = (CheckBox)GridView1.Rows[i].Cells[0].FindControl("chkSelect");
TextBox txtAmount = (TextBox)GridView1.Rows[i].Cells[5].FindControl("txtAmount");
if (chkUpdate != null)
{
if (chkUpdate.Checked)
{
string strID = GridView1.Rows[i].Cells[1].Text;
GridView1.Rows[i].FindControl("txtLocation")).Text;
string text = this.GridView1.Rows[i].Cells[1].Text;
string[] strArrays = new string[] { "INSERT INTO [OrderCancel]
([OrderID],
[Message],
[Type],
[RelationProductID],
[Amount])
VALUES(" ,
Request.QueryString["o"] ,
",'" , txtWhy.Text ,
"',",type.ToString(),",
" , strID , "," ,
txtAmount.Text , ");" };
stringBuilder.Append(string.Concat(strArrays));
//append update statement in stringBuilder
stringBuilder.Append(string.Concat(strArrays));
}
}
try
{
try
{
sqlCommand.CommandType = CommandType.Text;
sqlCommand.CommandText = stringBuilder.ToString();
sqlCommand.Connection = sqlConnection;
sqlConnection.Open();
sqlCommand.ExecuteNonQuery();
}
catch (SqlException sqlException)
{
throw new Exception(string.Concat("Error in Updation",
sqlException.Message));
}
}
finally
{
sqlConnection.Close();
}
Your code could be cleaned up, you could do the following:
private readonly string dbConnection = "...";
private const string query = "... Column = #Column";
For the sake of brevity I've added ... which will correlate to your Connection String and your query with parameters.
var message = String.Empty;
using(var connection = new SqlConnection(dbConnection))
using(var command = new SqlCommand(query, dbConnection))
{
connection.Open();
command.CommandType = CommandType.Text;
command.Parameters.Add("#Column", SqlDbType.NVarChar).Value = message;
command.ExecuteNonQuery();
}
So that small snippet would be inside of a method, which would pass a model of the data in your Grid. Then when you pass a value from your Grid, then you would build your model and pass to the method which will write to your database.
Also, when you use a StringBuilder you will also need to call ToString(); to ensure that it is a string rather than a StringBuilder when your utilizing.
This error usually happens if you do not set the commandText property. looking at your code it looks like your stringbuilder variable is not getting set. have you tried putting a breakpoint inside your "chkUpdate.Checked" loop? if yes, can you post the sql that gets constructed in your loop
in my code the user can upload an excel document wish contains it's phone contact list.Me as a developer should read that excel file turn it into a dataTable and insert it into the database .
The Problem is that some clients have a huge amount of contacts like saying 5000 and more contacts and when i am trying to insert this amount of data into the database it's crashing and giving me a timeout exception.
What would be the best way to avoid this kind of exception and is their any code that can reduce the time of the insert statement so the user don't wait too long ?
the code
public SqlConnection connection = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);
public void Insert(string InsertQuery)
{
SqlDataAdapter adp = new SqlDataAdapter();
adp.InsertCommand = new SqlCommand(InsertQuery, connection);
if (connection.State == System.Data.ConnectionState.Closed)
{
connection.Open();
}
adp.InsertCommand.ExecuteNonQuery();
connection.Close();
}
protected void submit_Click(object sender, EventArgs e)
{
string UploadFolder = "Savedfiles/";
if (Upload.HasFile) {
string fileName = Upload.PostedFile.FileName;
string path=Server.MapPath(UploadFolder+fileName);
Upload.SaveAs(path);
Msg.Text = "successfully uploaded";
DataTable ValuesDt = new DataTable();
ValuesDt = ConvertExcelFileToDataTable(path);
Session["valuesdt"] = ValuesDt;
Excel_grd.DataSource = ValuesDt;
Excel_grd.DataBind();
}
}
protected void SendToServer_Click(object sender, EventArgs e)
{
DataTable Values = Session["valuesdt"] as DataTable ;
if(Values.Rows.Count>0)
{
DataTable dv = Values.DefaultView.ToTable(true, "Mobile1", "Mobile2", "Tel", "Category");
double Mobile1,Mobile2,Tel;string Category="";
for (int i = 0; i < Values.Rows.Count; i++)
{
Mobile1 =Values.Rows[i]["Mobile1"].ToString()==""?0: double.Parse(Values.Rows[i]["Mobile1"].ToString());
Mobile2 = Values.Rows[i]["Mobile2"].ToString() == "" ? 0 : double.Parse(Values.Rows[i]["Mobile2"].ToString());
Tel = Values.Rows[i]["Tel"].ToString() == "" ? 0 : double.Parse(Values.Rows[i]["Tel"].ToString());
Category = Values.Rows[i]["Category"].ToString();
Insert("INSERT INTO client(Mobile1,Mobile2,Tel,Category) VALUES(" + Mobile1 + "," + Mobile2 + "," + Tel + ",'" + Category + "')");
Msg.Text = "Submitied successfully to the server ";
}
}
}
You can try SqlBulkCopy to insert Datatable to Database Table
Something like this,
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(sqlConnection, SqlBulkCopyOptions.KeepIdentity))
{
bulkCopy.DestinationTableName = DestTableName;
string[] DtColumnName = YourDataTableColumns;
foreach (string dbcol in DbColumnName)//To map Column of Datatable to that of DataBase tabele
{
foreach (string dtcol in DtColumnName)
{
if (dbcol.ToLower() == dtcol.ToLower())
{
SqlBulkCopyColumnMapping mapID = new SqlBulkCopyColumnMapping(dtcol, dbcol);
bulkCopy.ColumnMappings.Add(mapID);
break;
}
}
}
bulkCopy.WriteToServer(YourDataTableName.CreateDataReader());
bulkCopy.Close();
}
For more Read http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlbulkcopy.aspx
You are inserting 1 row at a time, which is very expensive for this amount of data
In those cases you should use bulk insert, so the round trip to DB will be only once, if you need to roll back - all is the same transaction
You can use SqlBulkCopy which is more work, or you can use the batch update feature of the SqlAdpater. Instead of creating your own insert statement, then building a sqladapter, and then manually executing it, create a dataset, fill it, create one sqldataadpater, set the number of inserts in a batch, then execute the adapter once.
I could repeat the code, but this article shows exactly how to do it: http://msdn.microsoft.com/en-us/library/kbbwt18a%28v=vs.80%29.aspx
protected void SendToServer_Click(object sender, EventArgs e)
{
DataTable Values = Session["valuesdt"] as DataTable ;
if(Values.Rows.Count>0)
{
DataTable dv = Values.DefaultView.ToTable(true, "Mobile1", "Mobile2", "Tel", "Category");
//Fix up default values
for (int i = 0; i < Values.Rows.Count; i++)
{
Values.Rows[i]["Mobile1"] =Values.Rows[i]["Mobile1"].ToString()==""?0: double.Parse(Values.Rows[i]["Mobile1"].ToString());
Values.Rows[i]["Mobile2"] = Values.Rows[i]["Mobile2"].ToString() == "" ? 0 : double.Parse(Values.Rows[i]["Mobile2"].ToString());
Values.Rows[i]["Tel"] = Values.Rows[i]["Tel"].ToString() == "" ? 0 : double.Parse(Values.Rows[i]["Tel"].ToString());
Values.Rows[i]["Category"] = Values.Rows[i]["Category"].ToString();
}
BatchUpdate(dv,1000);
}
}
public static void BatchUpdate(DataTable dataTable,Int32 batchSize)
{
// Assumes GetConnectionString() returns a valid connection string.
string connectionString = GetConnectionString();
// Connect to the database.
using (SqlConnection connection = new SqlConnection(connectionString))
{
// Create a SqlDataAdapter.
SqlDataAdapter adapter = new SqlDataAdapter();
// Set the INSERT command and parameter.
adapter.InsertCommand = new SqlCommand(
"INSERT INTO client(Mobile1,Mobile2,Tel,Category) VALUES(#Mobile1,#Mobile2,#Tel,#Category);", connection);
adapter.InsertCommand.Parameters.Add("#Mobile1",
SqlDbType.Float);
adapter.InsertCommand.Parameters.Add("#Mobile2",
SqlDbType.Float);
adapter.InsertCommand.Parameters.Add("#Tel",
SqlDbType.Float);
adapter.InsertCommand.Parameters.Add("#Category",
SqlDbType.NVarchar, 50);
adapter.InsertCommand.UpdatedRowSource = UpdateRowSource.None;
// Set the batch size.
adapter.UpdateBatchSize = batchSize;
// Execute the update.
adapter.Update(dataTable);
}
}
I know this is a super old post, but you should not need to use the bulk operations explained in the existing answers for 5000 inserts. Your performance is suffering so much because you close and reopen the connection for each row insert. Here is some code I have used in the past that keeps one connection open and executes as many commands as needed to push all the data to the DB:
public static class DataWorker
{
public static Func<IEnumerable<T>, Task> GetStoredProcedureWorker<T>(Func<SqlConnection> connectionSource, string storedProcedureName, Func<T, IEnumerable<(string paramName, object paramValue)>> parameterizer)
{
if (connectionSource is null) throw new ArgumentNullException(nameof(connectionSource));
SqlConnection openConnection()
{
var conn = connectionSource() ?? throw new ArgumentNullException(nameof(connectionSource), $"Connection from {nameof(connectionSource)} cannot be null");
var connState = conn.State;
if (connState != ConnectionState.Open)
{
conn.Open();
}
return conn;
}
async Task DoStoredProcedureWork(IEnumerable<T> workData)
{
using (var connection = openConnection())
using (var command = connection.CreateCommand())
{
command.CommandType = CommandType.StoredProcedure;
command.CommandText = storedProcedureName;
command.Prepare();
foreach (var thing in workData)
{
command.Parameters.Clear();
foreach (var (paramName, paramValue) in parameterizer(thing))
{
command.Parameters.AddWithValue(paramName, paramValue ?? DBNull.Value);
}
await command.ExecuteNonQueryAsync().ConfigureAwait(false);
}
}
}
return DoStoredProcedureWork;
}
}
This was actually from a project where I was gathering emails for a restriction list, so kind of relevant example of what a parameterizer argument might look like and how to use the above code:
IEnumerable<(string,object)> RestrictionToParameter(EmailRestriction emailRestriction)
{
yield return ("#emailAddress", emailRestriction.Email);
yield return ("#reason", emailRestriction.Reason);
yield return ("#restrictionType", emailRestriction.RestrictionType);
yield return ("#dateTime", emailRestriction.Date);
}
var worker = DataWorker.GetStoredProcedureWorker<EmailRestriction>(ConnectionFactory, #"[emaildata].[AddRestrictedEmail]", RestrictionToParameter);
await worker(emailRestrictions).ConfigureAwait(false);
I have a form with a text box and button, such that when the user clicks the button, the specified name in the text box is added to a table in my sql database. The code for the button is as follows:
private void btnAddDiaryItem_Click(object sender, EventArgs e)
{
try
{
string strNewDiaryItem = txtAddDiaryItem.Text;
if (strNewDiaryItem.Length == 0)
{
MessageBox.Show("You have not specified the name of a new Diary Item");
return;
}
string sqlText = "INSERT INTO tblDiaryTypes (DiaryType) VALUES = ('" + strNewDiaryItem + "');";
cSqlQuery cS = new cSqlQuery(sqlText, "non query");
PopulateInitialDiaryItems();
MessageBox.Show("New Diary Item added succesfully");
}
catch (Exception ex)
{
MessageBox.Show("Unhandled Error: " + ex.Message);
}
}
The class cSqlQuery is a simple class that executes various T-SQL actions for me and its code is as follows:
class cSqlQuery
{
public string cSqlStat;
public DataTable cQueryResults;
public int cScalarResult;
public cSqlQuery()
{
this.cSqlStat = "empty";
}
public cSqlQuery(string paramSqlStat, string paramMode)
{
this.cSqlStat = paramSqlStat;
string strConnection = BuildConnectionString();
SqlConnection linkToDB = new SqlConnection(strConnection);
if (paramMode == "non query")
{
linkToDB.Open();
SqlCommand sqlCom = new SqlCommand(paramSqlStat, linkToDB);
sqlCom.ExecuteNonQuery();
linkToDB.Close();
}
if (paramMode == "table")
{
using (linkToDB)
using (var adapter = new SqlDataAdapter(cSqlStat, linkToDB))
{
DataTable table = new DataTable();
adapter.Fill(table);
this.cQueryResults = table;
}
}
if (paramMode == "scalar")
{
linkToDB.Open();
SqlCommand sqlCom = new SqlCommand(paramSqlStat, linkToDB);
this.cScalarResult = (Int32)sqlCom.ExecuteScalar();
linkToDB.Close();
}
}
public cSqlQuery(SqlCommand paramSqlCom, string paramMode)
{
string strConnection = BuildConnectionString();
SqlConnection linkToDB = new SqlConnection(strConnection);
paramSqlCom.Connection = linkToDB;
if (paramMode == "table")
{
using (linkToDB)
using (var adapter = new SqlDataAdapter(paramSqlCom))
{
DataTable table = new DataTable();
adapter.Fill(table);
this.cQueryResults = table;
}
}
if (paramMode == "scalar")
{
linkToDB.Open();
paramSqlCom.Connection = linkToDB;
this.cScalarResult = (Int32)paramSqlCom.ExecuteScalar();
linkToDB.Close();
}
}
public string BuildConnectionString()
{
cConnectionString cCS = new cConnectionString();
return cCS.strConnect;
}
}
The class works well throughout my application so I don't think the error is in the class, but then I can't be sure.
When I click the button I get the following error message:
Incorrect syntax near =
Which is really annoying me, because when I run the exact same command in SQL Management Studio it works fine.
I'm sure I'm missing something rather simple, but after reading my code through many times, I'm struggling to see where I have gone wrong.
you have to remove = after values.
string sqlText = "INSERT INTO tblDiaryTypes (DiaryType) VALUES ('" + strNewDiaryItem + "');"
and try to use Parameterized queries to avoid Sql injection. use your code like this. Sql Parameters
string sqlText = "INSERT INTO tblDiaryTypes (DiaryType) VALUES (#DairyItem);"
YourCOmmandObj.Parameters.AddwithValue("#DairyItem",strNewDiaryIItem)
Remove the = after VALUES.
You do not need the =
A valid insert would look like
INSERT INTO table_name (column1, column2, column3,...)
VALUES (value1, value2, value3,...)
Source: http://www.w3schools.com/sql/sql_insert.asp
Please use following:
insert into <table name> Values (value);
Remove "=", and also i would recommend you to use string.format() instead of string concatenation.
sqlText = string.format(INSERT INTO tblDiaryTypes (DiaryType) VALUES ('{0}'), strNewDiaryItem);"
I'm creating an auditting table, and I have the easy Insert and Delete auditting methods done. I'm a bit stuck on the Update method - I need to be able to get the current values in the database, the new values in the query parameters, and compare the two so I can input the old values and changed values into a table in the database.
Here is my code:
protected void SqlDataSource1_Updating(object sender, SqlDataSourceCommandEventArgs e)
{
string[] fields = null;
string fieldsstring = null;
string fieldID = e.Command.Parameters[5].Value.ToString();
System.Security.Principal. WindowsPrincipal p = System.Threading.Thread.CurrentPrincipal as System.Security.Principal.WindowsPrincipal;
string[] namearray = p.Identity.Name.Split('\\');
string name = namearray[1];
string queryStringupdatecheck = "SELECT VAXCode, Reference, CostCentre, Department, ReportingCategory FROM NominalCode WHERE ID = #ID";
string queryString = "INSERT INTO Audit (source, action, itemID, item, userid, timestamp) VALUES (#source, #action, #itemID, #item, #userid, #timestamp)";
using (SqlConnection connection = new SqlConnection("con string = deleted for privacy"))
{
SqlCommand commandCheck = new SqlCommand(queryStringupdatecheck, connection);
commandCheck.Parameters.AddWithValue("#ID", fieldID);
connection.Open();
SqlDataReader reader = commandCheck.ExecuteReader();
while (reader.Read())
{
for (int i = 0; i < reader.FieldCount - 1; i++)
{
if (reader[i].ToString() != e.Command.Parameters[i].Value.ToString())
{
fields[i] = e.Command.Parameters[i].Value.ToString() + "Old value: " + reader[i].ToString();
}
else
{
}
}
}
fieldsstring = String.Join(",", fields);
reader.Close();
SqlCommand command = new SqlCommand(queryString, connection);
command.Parameters.AddWithValue("#source", "Nominal");
command.Parameters.AddWithValue("#action", "Update");
command.Parameters.AddWithValue("#itemID", fieldID);
command.Parameters.AddWithValue("#item", fieldsstring);
command.Parameters.AddWithValue("#userid", name);
command.Parameters.AddWithValue("#timestamp", DateTime.Now);
try
{
command.ExecuteNonQuery();
}
catch (Exception x)
{
Response.Write(x);
}
finally
{
connection.Close();
}
}
}
The issue I'm having is that the fields[] array is ALWAYS null. Even though the VS debug window shows that the e.Command.Parameter.Value[i] and the reader[i] are different, the fields variable seems like it's never input into.
Thanks
You never set your fields[] to anything else than null, so it is null when you are trying to access it. You need to create the array before you can assign values to it. Try:
SqlDataReader reader = commandCheck.ExecuteReader();
fields = new string[reader.FieldCount]
I don't really understand what your doing here, but if your auditing, why don't you just insert every change into your audit table along with a timestamp?
Do fields = new string[reader.FieldCount] so that you have an array to assign to. You're trying to write to null[0].