I have a database which i insert some data into. The problem i have is that it will add more data then it should.
When the logfordb.pos is increasing it will add all prevoius data one more time and next time it will add even more.
Here is the code... with some reduction of conn string and parametres.
public void WriteToDatabase(DatabaseLog logfordb)
{
conn.Open();
var cmd = new SqlCommand();
cmd.CommandText = "Insert INTO [X] (Y, Z, C " + "Values (#val1, #val2, #val3";
for (int index = 0; index < logfordb.ListofDB[logfordb.pos].X.Count; index++)
{
cmd.Connection = conn;
cmd.Parameters.Clear();
if (logfordb.ListofDB[logfordb.pos].X[index].Details != null)
{
cmd.Parameters.AddWithValue("#val1", logfordb.ListofDB[logfordb.pos].X[index].Details.Age);
cmd.Parameters.AddWithValue("#val2", logfordb.ListofDB[logfordb.pos].X[index].Details.Name);
cmd.Parameters.AddWithValue("#val3", logfordb.ListofDB[logfordb.pos].X[index].Details.Etc);
cmd.ExecuteNonQuery();
}
}
conn.Close();
logfordb.pos += 1;
}
It seems like you want to change the value of logfordb.pos I think you want to pass logfordb by ref. I suspect the value isn't changing and the second time you call this function you end up adding the same data again because the value outside of this scope isn't being changed just a local copy that the function sees (and then exists destroying references to the changes).
Your code iterates through the entire logfordb every single time this is called.
You have three options:
At the end of this method, clear the logfordb entirely. (probably makes the most sense)
Add a starting position parameter, and let the calling code decide the position to start pushing the logfordb records into the database.
Add a "Stored" property to each record inside logfordb so that you can set it when that individual record has been stored and not push that record again.
Out of those, option 1 is probably your safest bet.
Related
I am developing a cricket simulation and i need to retrieve certain statistics from a players data. I've got the following code.
public List<float> BattingData()
{
con.ConnectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString.ToString();
string query = "SELECT [INNS], [NOT OUTS], [AVG] FROM [" + batTeam + "] WHERE [Player] = '" + name + "';";
SqlCommand com = new SqlCommand(query, con);
con.Open();
using (SqlDataReader reader = com.ExecuteReader())
{
if(reader.HasRows)
{
while (reader.NextResult())
{
Innings = Convert.ToInt32(reader["INNS"]);
NotOuts = Convert.ToInt32(reader["NOT OUTS"]);
Avg = Convert.ToSingle(reader["AVG"]);
}
}
}
con.Close();
OutRatePG = (Innings = NotOuts) / Innings;
OutRatePB = OutRatePG / 240;
RunsPB = Avg / 240;
battingData.Add(OutRatePB);
battingData.Add(RunsPB);
return battingData;
}
The error that I am getting is that when I try to divie by 'Innings' it is saying cannot divide by zero, so I think the variables are being returned as zero and no data is being assigned to them.
This line is the issue:
while (reader.NextResult())
What this does is move the reader to the next resultset, ignoring the rest of the rows unread. To advance a reader to the next row, you need to call reader.Read() instead.
You have some other issues with your code:
You appear to have a separate table for each team. This is incorrect database design. You should create a Team table, with each team in it, and then foreign key your TeamResults table to it. Query it using INNER JOIN.
You are concatenating user-entered values to your query. This leaves you open to SQL injection attacks. Use parameters instead. (You cannot parameterize a table name, another reason you should do as above 1.)
You do not need to check for HasRows. If there are no rows, Read() will return false.
It looks like you only want one row. If that is the case you don't want a while(reader.Read()) loop, instead if(reader.Read()). (If you only need a single value, you can refactor the code to use command.ExecuteScalar().)
In database records check if value for Innings has 0
also you can try the below code before performing any operation.
> if(Innings>0) { OutRatePG = (Innings - NotOuts) / Innings; }
I have a one column table to keep track of number of visits. In Global.asax.cs I attempt to increment this value by 1 inside application_start but the field does't get updated. I get no exceptions but number of rows affected is always zero.
I tried the same simple query in SSMS and I get the same thing: 0 rows affected.
There is one int column in that table called NumVisits.
This is part of Application_Start in Global.asax.cs:
Application.Lock();
int iNumVisits = SomeClass.GetNumVisits();
SomeClass.UpdateNumVists(iNumVisits + 1);
Application.UnLock();
This is in SomeClass (BLL):
public static void UpdateNumVists(int iNumVisists)
{
LocaleRepository oLocaleRepository = new LocaleRepository(new SqlDbContext());
oLocaleRepository.UpdateNumVists(iNumVisists);
}
and this is in DAL:
public void UpdateNumVists(int iNumVisits)
{
int iRet = 0;
try
{
dbContext.Open();
List<SqlParameter> spParams = new List<SqlParameter>();
string sQuery = "update Visits set NumVisits = #NumVisits";
spParams.Add(dbContext.CreateSqlParam("#NumVisits", SqlDbType.Int, 0, iNumVisits));
dbContext.ExecuteSqlNonQuery(sQuery, spParams, ref iRet);
}
catch (Exception e)
{
throw e;
}
finally
{
dbContext.Close();
}
return;
}
I use the following for all commands using executeNonQuery:
public void ExecuteSqlNonQuery(string sQuery, List<SqlParameter> spParams, ref int iRet)
{
using (SqlCommand command = new SqlCommand())
{
command.CommandType = CommandType.Text;
command.Parameters.AddRange(spParams.ToArray<SqlParameter>());
command.Connection = DbConnection;
command.CommandText = sQuery;
try
{
iRet = command.ExecuteNonQuery();
}
catch(Exception e)
{ }
}
}
when the update command is executed, iRet is zero. I can't see why a simple update query would not work.
This is the create script I got from SSMS:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Visits](
[NumVisits] [int] NULL
) ON [PRIMARY]
GO
In general there are a few possible reasons why an update would not happen.
First, if the field is also an identity or calculated field, an ordinary update is not going to work. This doesn't look to be your case, but it is good to know for the future.
Next if there is a trigger on the table, it may be preventing the update. SSMS doesn't necessarily script triggers out when you script a table, so I can't tell if you have a trigger.
Third And most common, your application may not be sending what you expect as the update statement or even communicating with the database at all when you expect it to. This is often true when there is a problem of nulls. If your variable is not properly populating, then you may indeed be updating a null value to a null value. Run Profiler to capture exactly what is being sent when you try to do the update. Often when you see the statement that is actually being run, you will see the problem. Sometimes it is a matter of a missing space, sometimes a variable that was not populated that you thought was populated, etc.
Another possibility is that the user running the code has no update rights to the table. You should have gotten a message if this were the case.
If you have run Profiler, try running that exact code in SSMS and see if it updates. Sometimes you get a better error bubble up when you do that. Especially if your error handling in the application code is not well designed.
Of course if the table has no data, you need to do an insert not an update. Or the update might not be finding any records to update, try doing a select using the same conditions and it may turn out there is not record to update.
It seems like there is no data in the table, are there any records in Visits?
i insert the data from datagridview to database table. but the error that come in the exception i write in the title. the value save in the database table as well.
private void btnSavePurchases_Click(object sender, EventArgs e)
{
if ((string.IsNullOrEmpty(txtPGrandTotal.Text)) || (txtPGrandTotal.Text == "0"))
{
MessageBox.Show("No record available");
}
else
{
try
{
string query1 = "INSERT INTO purchases (productId) values (#product_Id)";
command = DBConnectivity.getCommandForQuery(query1, connection);
for (int i = 0; i < dGvPurchases.Rows.Count; i++)
{
// command.Parameters.Clear();
command.Parameters.AddWithValue("product_Id", dGvPurchases.Rows[i].Cells[9].Value);
command.ExecuteNonQuery();
}
}
catch (Exception ex)
{
}
}
}
Probably
AddWithValue("product_Id"...
should be
AddWithValue("#product_Id"...
By the way, since you add your parameters in a for loop, you need clear them top of your for loop. That's why you need to uncomment your command.Parameters.Clear() part. Without Clear method, you try to add same parameter name over and over again to same command and you will get an error in your second iteration.
As an another solution, you can declare your parameter name outside of your loop and add it's value inside of loop.
And don't use AddWithValue as much as possible. It may generate unexpected results sometimes. Use .Add() overloads to specify your db type and it's size.
Don't forget to use using statement as well to dispose your command object.
I don't see command anywhere in the scope here. Probably it is a class variable. That is one part of your issue.
Move the construction of the command variable to inside your method:
var command = DBConnectivity.getCommandForQuery(...);
^^^
Second, your for look causes issues. You can't add the same parameter over and over again. If you want to insert multiple rows, add multiple insert statements. Create the command inside the for loop.
problem is that command.Parameters.AddWithValue adds the parameter to the list of parameters. you can't add a parameter twice. since you call the command several times, define the parameter outside and set value within the loop:
string query1 = "INSERT INTO purchases (productId) values (#product_Id)";
command = DBConnectivity.getCommandForQuery(query1, connection);
// Define the Parameter just once
var param = command.Parameters.Add("#product_Id", SqlDbType.Int);
for (int i = 0; i < dGvPurchases.Rows.Count; i++)
{ // set value while looping
param.Value = dGvPurchases.Rows[i].Cells[9].Value;
command.ExecuteNonQuery();
}
So im trying to write my list to a database and ive got some questions. First of all nothing seems to get saved into the database but theres no errors that would cause a crash sofar and I know for a fact that this piece of code has worked in the past for me:
public void saveToDb(int var1, string var2)
{
SqlCommand cmd = new SqlCommand("Insert into [table] (col1, col2) VALUES (#param1, #param2)", conn);
cmd.Parameters.AddWithValue("#param1", var1);
cmd.Parameters.AddWithValue("#param2", var2);
cmd.Connection.Open();
cmd.ExecuteNonQuery();
cmd.Connection.Close();
}
I have a three piece layer going on, ui, logic and DAL. First of all it didnt work with the database and the app.config files in the DAL class library so those were moved to the main class library and now its not whining about the database already existing and it finds my connection string.
To send the data into this method im doing it this way:
for (int i = 0; i < myList.Count; i++)
{
da.saveToDb(myList.val1, myList.val2);
}
Its not giving me an error in the code but nothing seems to be saved or is resetted when I stop the program but I dont know which but I can see the variable being passed correctly by printing them before doing the insert so im guessing the Db is resetted? Is it putting my db into the debug folder and flushing it everytime or what?
Another thing is last time I did this it was a form so there was always going to be just one insert at a time, right now my list of objects could contain anywhere from 1 to alot of objects and with this way I would be opening and closing the db connection once for each object in my list right? How do you do bulk inserts? Been reading about datasets but they all seem to be about reading from a database not writing so im not sure about that. I did read from a database in another project using Dataset and adapter so that shouldnt be a problem but how do I bulk send a list into a table? To make it abit more tricky I cant just convert the entire list because of 10 propertys 8 is going to go into one table and the remaining 2 is to go in a second table so I would need to loop them and add the respective property to the respective dataset (or what you use).
edit
Well ive now made some adjustments and im trying two methods and none of which work but neither gives an error either which is getting frustrating.
First method:
public void saveToDb(int val1, string val2)
{
SqlConnection conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["[MyConnectionString]"].ConnectionString);
SqlCommand cmd = new SqlCommand("Insert into [table] (val1, val2) VALUES (#param1, #param2)", conn);
cmd.Parameters.AddWithValue("#param1", val1);
cmd.Parameters.AddWithValue("#param2", val2);
cmd.Connection.Open();
cmd.ExecuteNonQuery();
cmd.Connection.Close();
}
And the second I try to sqlbulkcopy a table:
public void SaveToDb()
{
using (SqlConnection conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["[MyConnectionString]"].ConnectionString))
{
conn.Open();
using (SqlBulkCopy bulk = new SqlBulkCopy(conn))
{
bulk.ColumnMappings.Add("col1", "col1");
bulk.ColumnMappings.Add("col2", "col1");
bulk.DestinationTableName = "[table]";
System.Diagnostics.Debug.Print("Open");
bulk.WriteToServer(tab);
foreach (DataRow row in tab.Rows)
{
foreach (var item in row.ItemArray)
{
System.Diagnostics.Debug.Print(item.ToString());
}
}
System.Diagnostics.Debug.Print("sending");
}
System.Diagnostics.Debug.Print("closing");
}
}
I shouldnt have to map it since the table contains the exact same columns as the table with the same naming (upper/lower case) but it gets weird with the primary key which increments so I mapped it so it should add the increment automatically but nothing gets inserted, the print sure enough shows the values but if I comment out the mapping I get an error saying that null cant be assigned (which is true my table wont take nulls) but the value shouldnt be null since its there in the table?
It seems you forgot the index.
for (int i = 0; i < myList.Count; i++)
{
da.saveToDb(myList[i].val1, myList[i].val2);
}
I think you are missing the connection object.
var cn = new SqlConnection().
Then you call open on the connection object.
connection.command will give access to the command object.
private void btnGo_Click(object sender, EventArgs e)
{
Array IDlist = txtUserID.Text.Split(new char[] { });
ArrayList badID = new ArrayList();
foreach (string textLine in IDlist)
{
try
{
int LineID = Convert.ToInt32(textLine);
string emp = txtDistricts.Text;
command.Parameters.Add("#EmpID", SqlDbType.Int).Value = LineID;
if (!emp.Equals(string.Empty))
command.Parameters.Add("#SchoolDistricts", SqlDbType.NVarChar).Value = emp;
else command.Parameters.Add("#SchoolDistricts", SqlDbType.NVarChar).Value = DBNull.Value;
if (cbRemove.Checked)
command.Parameters.Add("#Options", SqlDbType.Int).Value = 1;
else if (cbReset.Checked)
command.Parameters.Add("#Options", SqlDbType.Int).Value = 0;
else command.Parameters.Add("#Options", SqlDbType.Int).Value = DBNull.Value;
SqlParameter returnValue = new SqlParameter("#return_value", DbType.String);
returnValue.Direction = ParameterDirection.ReturnValue;
command.Parameters.Add(returnValue);
conn.Open();
command.Connection = conn;
// command.ExecuteNonQuery();
command.ExecuteScalar();
String OutPutCheck = (command.Parameters["#return_value"].Value.ToString());
String getCheck = (command.ExecuteScalar().ToString());
OPBox.Text += LineID + "--->>" + OutPutCheck + "--->>" + getCheck + "\n";
conn.Close();
//flagUser(LineID, emp);
}
catch (Exception ex)
{
//stored procedure error
badID.Add(textLine);
conn.Close();
}
}}
I made an APP , which takes bunch of ID at a time. After btn_click these values put in array. Then from array each ID pass to store procedure one by one, and get return value. well First value give return value, but after that when second value pass to store procedure it gives following error.
> ERROR::::ex = {"Procedure or function
> usp_Flag_Employee has too many
> arguments specified."}
You keep adding parameters to your command object without reseting it. You should move your connection and command objects into the method where they are being called and use 'using' statements.
Because your connection and command are class fields, each instance of the loop is re-adding the parameters to the old set of parameters. At minimum, reset the parameters collection at the top of the loop.
You are passing too many parameters to the procedure. If you paste the procedure code we can help identify, however just do a count of the params and check to ensure you have all defined in the proc.
I don't see any code generating the SqlCommand object in your example.
If command is local to the class, there's a very good chance that it has already been used (which means it probably already has parameters added to it).
I also see no code that sets the command type to StoredProcedure. Depending on what the command text is, this could be the issue as well (if you're simply passing the stored procedure name without setting the type...it will see the command as having no parameters).
Re-Writing the code to use its own SqlConnection and SqlCommand would make this much easier to debug (unless, of course, it already is and you didn't give us that code).
EDIT
I just noticed that you're using the code inside a foreach loop without clearing the parameters. That is yet another issue (and probably the most likely cause for this issue). Just be sure to call command.Parameters.Clear() at the beginning of each loop before adding the new parameters.
Call the Clear method before adding the parameters.
It works the first time because your command object has no parameters. For each subsequent iteration you keep on adding another set of parameters to your command object.
You need to clear the parameters for your command object on each iteration.