I am trying to execute a stored procedure in asp.net. The stored procedure requires 3 parameters, all 3 are ID's(ints). The 3 parameters are : TaskID, ExhibitID, and InvestigatorID.
I have a hidden field that contains an array of ExhibitID's that came from a javascript function.
My question is how do I get the query to execute as I am looping through the array?
Here is an example of my stored procedure:
var cnSaveTask = new SqlConnection(ConfigurationManager.ConnectionStrings["OSCIDConnectionString"].ToString());
var comLinkExhibitToTask = new SqlCommand("p_CaseFileTasksExhibitLinkAdd", cnSaveTask) { CommandType = CommandType.StoredProcedure };
foreach (string exhibit in hidExhibitsIDs.Value.Split(','))
{
comLinkExhibitToTask.Parameters.AddWithValue("#TaskID", taskID);
comLinkExhibitToTask.Parameters.AddWithValue("#ExhibitID", Convert.ToInt32(exhibit));
comLinkExhibitToTask.Parameters.AddWithValue("#InvestigatorID", int.Parse(Session["InvestigatorID"].ToString()));
}
try
{
cnSaveTask.Open();
comLinkExhibitToTask.ExecuteNonQuery();
}
It is not working in my DB though. Nothing gets added. My guess is that since it is iterating and not executing, it just keeps replacing the "exhibitID" everytime then eventually tries to execute it. But I don't think just adding "comLinkExhibitToTask.ExecuteNonQuery()"
outside the try is a good idea. Any suggestions?
you can either move the try block into the foreach loop or wrap the foreach loop with a try block. (depending on what error handling you wish - continue with the next exhibit on error or completely abort execution)
I've never used AddWithValue, so I can't speak to its functionality. Here's how I typically write a DB call like this.
using (SqlConnection cnSaveTask = new SqlConnection(ConfigurationManager.ConnectionStrings["OSCIDConnectionString"].ConnectionString))
{
cnSaveTask.Open();
using (SqlCommand comLinkExhibitToTask = new SqlCommand("p_CaseFileTasksExhibitLinkAdd", cnSaveTask))
{
comLinkExhibitToTask.CommandType = CommandType.StoredProcedure;
comLinkExhibitToTask.Parameters.Add(new SqlParameter("#TaskID", SqlDbType.Int) {Value = taskID});
// etc.
comLinkExhibitToTask.ExecuteNonQuery();
}
}
The solution:
var cnSaveTask = new SqlConnection(ConfigurationManager.ConnectionStrings["OSCIDConnectionString"].ToString());
try
{
var comLinkExhibitToTask = new SqlCommand("p_CaseFileTasksExhibitLinkAdd", cnSaveTask) { CommandType = CommandType.StoredProcedure };
cnSaveTask.Open();
comLinkExhibitToTask.Parameters.Add(new SqlParameter("#TaskID", SqlDbType.Int));
comLinkExhibitToTask.Parameters.Add(new SqlParameter("#ExhibitID", SqlDbType.Int));
comLinkExhibitToTask.Parameters.Add(new SqlParameter("#InvestigatorID", SqlDbType.Int));
foreach (string exhibit in hidExhibitsIDs.Value.Split(','))
{
comLinkExhibitToTask.Parameters["#TaskID"].Value = taskID;
comLinkExhibitToTask.Parameters["#ExhibitID"].Value = Convert.ToInt32(exhibit);
comLinkExhibitToTask.Parameters["#InvestigatorID"].Value = int.Parse(Session["InvestigatorID"].ToString());
comLinkExhibitToTask.ExecuteNonQuery();
}
}
catch (Exception ex)
{
ErrorLogger.Log(0, ex.Source, ex.Message);
}
finally
{
if (cnSaveTask.State == ConnectionState.Open)
{
cnSaveTask.Close();
}
}
Since I was in a loop it kept adding parameters. So just declare the parameters outside the loop, and only pass the values in the loop. That way there are only 3 parameters, and the values will be passed in accordingly
Related
Async method returns list with duplicated elements. It is async method which is using mysql connector to connect with database. Then it execute query (SELECT *) and by using MySqlDataReader - I save and add to list rows until last ReadAsync() call.
Asynchronous programming is still black magic for me - I would appreciate any feedback or indicating unlogical code lines with explanation.
This method will be used in my web api controller and method purpose is to return all entries from 'Posts' table. Code is working fine when I 'reset' temp object each loop by using
temp = new Post(); but I assume it is unacceptable ? What if my database would have not 15 but 15000 entries?
`
public async Task<List<Post>> GetPostsAsync()
{
List<Post> posts = new List<Post>();
Post temp = new Post();
try
{
await _context.conn.OpenAsync();
MySqlCommand cmd = new MySqlCommand("USE idunnodb; SELECT * FROM Posts;", _context.conn);
await using MySqlDataReader reader = await cmd.ExecuteReaderAsync();
while(await reader.ReadAsync())
{
temp.PostID = (int)reader[0];
temp.UserID = (int)reader[1];
temp.PostDate = reader[2].ToString();
temp.PostTitle = reader[3].ToString();
temp.PostDescription = reader[4].ToString();
temp.ImagePath = reader[5].ToString();
posts.Add(temp);
}
await _context.conn.CloseAsync();
}
catch (Exception ex)
{
return Enumerable.Empty<Post>().ToList();
}
return posts;
}
`
Looks like you can only read data by looping through MySqlDataReader, according to your code logic, you need to read each piece of data, and then add them to the List one by one for output.
Your code is behaving this way because temp has been declared & instantiated outside of your reader.ReadAsync() statement, you are updating the same object reference each time around the loop which is why you are seeing repeating objects in your list.
So you need to instantiate in reader.ReadAsync() loop:
while(await reader.ReadAsync())
{
Post temp = new Post();
...
}
How do I store the results from my stored procedure to variables? Here is my sample code:
public ActionResult ManageProfile(string eid)
{
var vm = new ManageProfileViewModel(); // Call ViewModel
sp_GetUserDetails_Result gResult = db_RIRO.sp_GetUserDetails(Session["EID"].ToString()).First();
// Get UserId, FirstName, LastName from stored procedure result
gResult.UserId = vm.UserId;
gResult.FirstName = vm.FirstName;
gResult.LastName = vm.LastName;
return View(vm);
}
The stored procedure works fine when I manually try to execute it in Management Studio. The problem with my code is after executing it returns a null.
Assigning of my variables should be the other way around.
vm.FirstName = gResult.SAPID
instead of
gResult.SAPID = vm.FirstName.
It is difficult to tell you without seeing the stored procedure.
Make sure your stored procedure has output parameter.
For example, if you have a output variable "#userId" from stored procedure:
something like in your code:
sqlcmd.Parameters.Add("#userId", SqlDbType.NVarChar, 4000).Value = "";
sqlcmd.Parameters["#userId"].Direction = ParameterDirection.Output;using
using (SqlConnection conn = new SqlConnection(dbConnStr))
{
sqlcmd.Connection = conn;
conn.Open();
sqlcmd.ExecuteNonQuery();
conn.Close();
if(sqlcmd.Parameters["#userId"].SqlValue.ToString() != "Null")
{
gResult.UserId = sqlcmd.Parameters["#userId"].SqlValue.ToString();
}
}
Hope this pseudo code helps you.
I am developing an ASP.NET MVC application. I have a stored procedure. I want to send some values to the stored procedure. Below are the parameters
#CorporateId Input
#CitizenId Input
#DocType Input
#Revert Input
#ResponseCode Out
#ResponseMessage Out
I need to send values for CorporateId ,CitizenId,DocType and #Revert where the value is 0 always. when inserting documents I want to send 0 as a value to #rever.
Sample code I've tried
public EmployeeDetail InsertDocumentFlagRevert(int? corporateID, string citizenId, int? docType, string connectingString)
{
string constring = connectingString;
EmployeeDetail objclValues = new EmployeeDetail();
using (SqlConnection con = new SqlConnection(constring))
{
using (SqlCommand cmd = new SqlCommand("uup_Employee_KYC_Uploaded_Flag", con))
{
cmd.CommandType = CommandType.StoredProcedure;
if (corporateID == null)
{
cmd.Parameters.AddWithValue("#CorporateID", DBNull.Value);
}
else
{
cmd.Parameters.AddWithValue("#CorporateID", corporateID);
}
if (string.IsNullOrEmpty(citizenId))
{
cmd.Parameters.AddWithValue("#CitizenId", DBNull.Value);
}
else
{
cmd.Parameters.AddWithValue("#CitizenId", citizenId);
}
if (docType == null)
{
cmd.Parameters.AddWithValue("#DocType", DBNull.Value);
}
else
{
cmd.Parameters.AddWithValue("#DocType", docType);
}
cmd.Parameters.Add("#ResponseCode", SqlDbType.VarChar, 2);
cmd.Parameters.Add("#ResponseMessage", SqlDbType.VarChar, 70);
cmd.Parameters.AddWithValue("#Revert", 0);
cmd.Parameters["#ResponseCode"].Direction = ParameterDirection.Output;
cmd.Parameters["#ResponseMessage"].Direction = ParameterDirection.Output;
con.Open();
int i = cmd.ExecuteNonQuery();
con.Close();
}
}
}
In this code, the value for i is -1. I am not sure if the parameters are actually being passed to the stored procedure or not? Can someone help me out with this?
As you know, ExecuteNonQuery returns the number of rows affected.
Try Commenting the SET NOCOUNT ON in your stored procedure.
This will return the number of affected rows. I hope this will help you resolve the issue.
You can either use SQL Profiler to inspect the query sent with parameters from your application to SQL Server.
Or, you can use the two output variables and inspect its values to make sure the parametres were sent correctly, the least is to append the parameter values in the #ResponseMessage parameter and check its value after the call for ExecuteNonQuery method
I have a web page that needs to update multiple records. This page gets all the information and then begins a transaction sending multiple UPDATE queries to the data base.
foreach row
{
Prepare the query
Hashtable Item = new Hashtable();
Item.Add("Id", Id);
Item.Add("Field1", Field1);
Item.Add("Field2", Field2);
Item.Add("Field3", Field3);
...
}
Then we launch the ytransaction
DO CHANGES()
public void execute_NonQuery_procedure_transaction(string StoredProcedure, List<Hashtable> Params)
{
using (MySqlConnection oConnection = new MySqlConnection(ConfigurationManager.AppSettings[DB]))
{
MySqlTransaction oTransaction;
bool HasErrors = false;
oConnection.Open();
oTransaction = oConnection.BeginTransaction();
try
{
MySqlCommand oCommand = new MySqlCommand(StoredProcedure, oConnection);
oCommand.CommandType = CommandType.StoredProcedure;
oCommand.Transaction = oTransaction;
foreach (Hashtable hParams in Params)
{
oCommand.Parameters.Clear();
IDictionaryEnumerator en = hParams.GetEnumerator();
while (en.MoveNext())
{
oCommand.Parameters.AddWithValue("_" + en.Key.ToString(), en.Value);
oCommand.Parameters["_" + en.Key.ToString()].Direction = ParameterDirection.Input;
}
oCommand.ExecuteNonQuery();
}
}
catch (Exception e)
{
HasErrors = true;
throw e;
}
finally
{
if (HasErrors)
oTransaction.Rollback();
else
oTransaction.Commit();
oConnection.Close();
}
}
}
Is there another way to do this or this is the most efficient way?
It depends on the situation, like if you have multiple row updates or adding new rows or deleting some rows or a combination of these, which modifies the database table then, the efficient way to do this is to have Batch Update...
Please go through this link Batch Update
Hope this helps...
it looks fine to me, you could eventually do not clear the Command.Parameters list but just assign the values on following iterations but probably this leads to no visible improvements.
pay attention your throw is wrong, in C# don't use throw e; but simply throw;.
I try to insert hundreds of records into empty database table using TableDirect type of SqlCeCommand. The problem is I get an exception SqlCeException "Unspecified error" when calling SqlCeResultSet::Insert. Below is my code. Any hints?
Thanks
public bool StoreEventsDB2(List<DAO.Event> events)
{
try
{
SqlCeCommand command = new SqlCeCommand("Event");
command.CommandType = System.Data.CommandType.TableDirect;
SqlCeResultSet rs = _databaseManager.ExecuteResultSet(command, ResultSetOptions.Updatable | ResultSetOptions.Scrollable );
foreach (DAO.Event theEvent in events)
{
SqlCeUpdatableRecord record = rs.CreateRecord();
record.SetInt32( 0, theEvent.ID );
record.SetInt32( 1, theEvent.ParentID);
record.SetString(2, theEvent.Name);
record.SetDateTime(3, theEvent.DateTime);
record.SetDateTime(4, theEvent.LastSynced);
record.SetInt32(5, theEvent.LastSyncedTS);
record.SetString(6, theEvent.VenueName);
record.SetBoolean(7, theEvent.IsParentEvent);
record.SetDateTime(11, DateTime.Now);
rs.Insert(record);
}
}
catch (SqlCeException e)
{
Log.Logger.GetLogger().Log(Log.Logger.LogLevel.ERROR, "[EventManager::StoreEventsDB] error: {0}", e.Message);
return false;
}
catch (Exception e)
{
Log.Logger.GetLogger().Log(Log.Logger.LogLevel.ERROR, "[EventManager::StoreEventsDB] error: {0}", e.Message);
return false;
}
return true;
}
I am unsure how your connection is managed with the database manager which could be the culprit - make sure you are using one connection (sqlce doesn't play nice). Also the results set option "ResultSetOption.Scrollable" is not needed (at least I have never used it for an insert).
Below is the syntax I use when doing direct table inserts. Every database/data access object is wrapped in a using statement to dispose of objects after use - this is very important especially with the compact framework and sqlce as the garbage collection is less than ideal (you WILL get out of memory exceptions!). I have added a transaction to your code also so that the option is all or nothing.
Hope this helps:
using (var transaction = connection.BeginTransaction())
{
using (var command = connection.CreateCommand())
{
command.Transaction = transaction;
command.CommandType = CommandType.TableDirect;
command.CommandText = "Event";
using (var rs = command.ExecuteResultSet(ResultSetOptions.Updatable))
{
var record = rs.CreateRecord();
foreach (DAO.Event theEvent in events)
{
record.SetInt32(0, theEvent.ID);
record.SetInt32(1, theEvent.ParentID);
record.SetString(2, theEvent.Name);
record.SetDateTime(3, theEvent.DateTime);
record.SetDateTime(4, theEvent.LastSynced);
record.SetInt32(5, theEvent.LastSyncedTS);
record.SetString(6, theEvent.VenueName);
record.SetBoolean(7, theEvent.IsParentEvent);
record.SetDateTime(11, DateTime.Now);
rs.Insert(record);
}
}
transaction.Commit();
}
}