Hi all below is my snippet of C# codes with multiple insert statement. I put them into a transaction bracket and I using prepared statement. My challenge for instance I know I got issue in now cmdText3 but there is no any error message generated. How in this scenario where should I be adding extra try and catch to help me debug and alert me on the error? Can in prepared statement I see what is the exact query being executed with the data?
myCon getMyCon1 = new myCon();
MySqlConnection con = getMyCon1.GetConnection();
using (MySqlTransaction trans = con.BeginTransaction())
{
try
{
long rID = 0;
String cmdText1 = "INSERT INTO record1(fiscalPeriod,financialYear) VALUES(#fiscalPeriod,#financialYear)";
using (MySqlCommand cmd = new MySqlCommand(cmdText1, con, trans))
{
cmd.Parameters.AddWithValue("#fiscalPeriod", fiscalPeriod.SelectedValue);
cmd.Parameters.AddWithValue("#financialYear", financialYear.SelectedValue);
cmd.ExecuteNonQuery();
cmd.Parameters.Clear();
rID = cmd.LastInsertedId;
}
foreach (object line in linesC)
{
if (line.GetType() == typeof(TypeC))
{
TypeC typesC = (TypeC)line;
String companyName = typesC.comName;
String periodStart = typesC.periodStart;
String periodEnd = typesC.periodEnd;
String cmdText2 = "INSERT INTO record2(rID,companyName,,periodStart,periodEnd,) VALUES(#rID,#companyName,#periodStart,#periodEnd)";
using (MySqlCommand cmd = new MySqlCommand(cmdText2, con, trans))
{
cmd.Parameters.AddWithValue("#rID", rID);
cmd.Parameters.AddWithValue("#companyName", companyName);
cmd.Parameters.AddWithValue("#periodStart", periodStart);
cmd.Parameters.AddWithValue("#periodEnd", periodEnd);
cmd.ExecuteNonQuery();
cmd.Parameters.Clear();
}
}
}
foreach (object line in linesP)
{
if (line.GetType() == typeof(TypeP))
{
TypeP typesP = (TypeP)line;
String supplierName = typesP.supName;
String invoiceDate = typesP.invoiceDate;
String invoiceNo = typesP.invoiceNo;
String cmdText3 = "INSERT INTO record2(rID,supplierName,invoiceDate,invoiceNo) VALUES(#rID,#supplierName,#invoiceDate,#invoiceNo,)";
using (MySqlCommand cmd = new MySqlCommand(cmdText3, con, trans))
{
cmd.Parameters.AddWithValue("#rID", rID);
cmd.Parameters.AddWithValue("#supplierName", supplierName);
cmd.Parameters.AddWithValue("#invoiceDate", invoiceDate);
cmd.Parameters.AddWithValue("#invoiceNo", invoiceNo);
cmd.ExecuteNonQuery();
cmd.Parameters.Clear();
}
}
}
trans.Commit();
}
catch (Exception ex)
{
trans.Rollback();
}
}
con.Close()
You can see the exact query using the Sql Profiler app. This will allow you to see both the queries generated and the responses from Sql Server.
https://msdn.microsoft.com/en-us/library/ms181091.aspx
The following:
String cmdText3 = "INSERT INTO record2(rID,supplierName,invoiceDate,invoiceNo) VALUES(#gafID,#supplierName,#invoiceDate,#invoiceNo,)";
Does not correspond with the first parameter you're specifying here:
cmd.Parameters.AddWithValue("#rID", rID);
cmd.Parameters.AddWithValue("#supplierName", supplierName);
cmd.Parameters.AddWithValue("#invoiceDate", invoiceDate);
cmd.Parameters.AddWithValue("#invoiceNo", invoiceNo);
Replace:
VALUES(#gafID,#supplierName,#invoiceDate,#invoiceNo,)
With:
VALUES(#rID,#supplierName,#invoiceDate,#invoiceNo)
Alternatively you can re-name:
cmd.Parameters.AddWithValue("#rID", rID);
To:
cmd.Parameters.AddWithValue("#gafID", rID);
Related
I have a very silly problem. I am doing a select, and I want that when the value comes null, return an empty string. When there is value in sql query, the query occurs all ok, but if there is nothing in the query, I have to give a sqlCommand.CommandTimeout greater than 300, and yet sometimes gives timeout. Have a solution for this?
public string TesteMetodo(string codPess)
{
var vp = new Classe.validaPessoa();
string _connection = vp.conString();
string query = String.Format("SELECT COUNT(*) FROM teste cliente WHERE cod_pess = {0}", codPess);
try
{
using (var conn = new SqlConnection(_connection))
{
conn.Open();
using (var cmd = new SqlCommand(query, conn))
{
SqlDataReader dr = cmd.ExecuteReader();
if(dr.HasRows)
return "";
return codPess;
}
}
}
You should probably validate in the UI and pass an integer.
You can combine the usings to a single block. A bit easier to read with fewer indents.
Always use parameters to make the query easier to write and avoid Sql Injection. I had to guess at the SqlDbType so, check your database for the actual type.
Don't open the connection until directly before the .Execute. Since you are only retrieving a single value you can use .ExecuteScalar. .ExecuteScalar returns an Object so must be converted to int.
public string TesteMetodo(string codPess)
{
int codPessNum = 0;
if (!Int32.TryParse(codPess, out codPessNum))
return "codPess is not a number";
var vp = new Classe.validaPessoa();
try
{
using (var conn = new SqlConnection(vp.conString))
using (var cmd = new SqlCommand("SELECT COUNT(*) FROM teste cliente WHERE cod_pess = #cod_pess", conn))
{
cmd.Parameters.Add("#cod_pess", SqlDbType.Int).Value = codPessNum;
conn.Open();
int count = (int)cmd.ExecuteScalar();
if (count > 0)
return "";
return codPess;
}
}
catch (Exception ex)
{
return ex.Message;
}
}
I have problem regarding inserting the loop process. So when the connection string determine that the server is down, the inserting process stop looping. My question, is there way to determine whether this connection string is down or not? I have research they answer is to make if condition sqlconn.State == ConnectionState.Open I will show you guys the sample error that I encounter.
string connetionString = null;
MySqlConnection cnn;
connetionString = "server=localhost;database=sample_db_xx;uid=root;pwd=;";
cnn = new MySqlConnection(connetionString);
try
{
var arpp_pro = new List<string>();
cnn.Open();
MySqlCommand command = new MySqlCommand("SELECT store_id,CONCAT(boh,'\\\\sqlexpress') as boh FROM db_cua.stores WHERE " +
"is_active = 1 AND boh != '' ", cnn);
using (MySqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine(reader[0].ToString());
arpp_pro.Add(reader[1].ToString());
}
}
cnn.Close();
foreach (var arpp_pro_data in arpp_pro)
{
string connetionString_SQL = #"Server=" + arpp_pro_data + " \sqlexpress;Database=Site5;User ID=sa;Password=dospos";
//#"Server=" + arpp_pro_data + ";Database=Site5;User ID=sa;Password=dospos";
var date_minus_one_day = DateTime.Today.AddDays(-1);
var formatted_date_minus_one_day = date_minus_one_day.ToString("yyyy-MM-dd");
var year = DateTime.Now.ToString("yyyy");
var month = DateTime.Now.ToString("MM");
var date = DateTime.Today.AddDays(-1);
var date_formatted = date.ToString("dd");
string get_sos_orders_details = #"SELECT
Convert(nvarchar(50),dbo.SOS_ORDERS.OrderId)+ '-'+ Convert(nvarchar(50),dbo.SOS_ORDERS.TransTime) + Convert(nvarchar(50),dbo.Sales.TransactionId)+ Convert(nvarchar(50),dbo.Sales.TotalDeptName) as result,
dbo.Sales.StoreId,
Convert(nvarchar(50),dbo.SOS_ORDERS.TransTime) as TransTime,
dbo.Transactions.OperatorName as Cashier,
dbo.Sales.TotalDeptName as Transaction_Type,
dbo.Sales.TransactionId,
(dbo.SOS_ORDERS.DTOT + dbo.SOS_ORDERS.ASSM) as Cashier_Time,
(dbo.SOS_ORDERS.KIT) as Preparation_Time,
(dbo.SOS_ORDERS.KIT + dbo.SOS_ORDERS.DTOT + dbo.SOS_ORDERS.ASSM) as Total_Time
FROM dbo.SOS_ORDERS INNER JOIN
dbo.Sales ON dbo.SOS_ORDERS.OrderId = dbo.Sales.StoredOrderIndex INNER JOIN
dbo.Transactions ON dbo.Sales.Sequence = dbo.Transactions.Sequence
where dbo.Sales.businessdate= #date_minus_one_day
OR(DATEPART(yy, dbo.SOS_ORDERS.TransTime) = #year
AND DATEPART(mm, dbo.SOS_ORDERS.TransTime) = #month
AND DATEPART(dd, dbo.SOS_ORDERS.TransTime) = #date_today )
AND(dbo.Sales.TotalDeptName in ('01 SALLE MANGER', '02 EMPORTER')
or dbo.Sales.TotalDeptName in ('01 DINE IN', '02 TAKE OUT'))
GROUP BY dbo.SOS_ORDERS.OrderId, dbo.Sales.StoreId, dbo.SOS_ORDERS.TransTime, dbo.SOS_ORDERS.DTOT, dbo.SOS_ORDERS.LINE, dbo.SOS_ORDERS.WIND, dbo.SOS_ORDERS.SERV, dbo.SOS_ORDERS.HOLD,
dbo.SOS_ORDERS.TOTL, dbo.SOS_ORDERS.ASSM, dbo.SOS_ORDERS.CASH, dbo.SOS_ORDERS.FTOT, dbo.SOS_ORDERS.PAY, dbo.SOS_ORDERS.KIT, dbo.Sales.TransactionId,
dbo.Transactions.OperatorName, dbo.Sales.TotalDeptName order by dbo.SOS_ORDERS.TransTime DESC";
using (SqlConnection sqlconn = new SqlConnection(connetionString_SQL))
{
sqlconn.Open();
if (sqlconn.State == ConnectionState.Open)
{
SqlCommand cmd = new SqlCommand(get_sos_orders_details, sqlconn);
cmd.Parameters.AddWithValue("#date_minus_one_day", formatted_date_minus_one_day);
cmd.Parameters.AddWithValue("#year", year);
cmd.Parameters.AddWithValue("#month", month);
cmd.Parameters.AddWithValue("#date_today", date_formatted);
SqlDataReader rs = cmd.ExecuteReader();
while (rs.Read())
{
// access your record colums by using reader
Console.WriteLine(rs["StoreId"]);
cnn.Open();
MySqlCommand comm = cnn.CreateCommand();
comm.CommandText = #"INSERT INTO master_data.so_v2 (StoreId,TransTime,Cashier,Transaction_Type,TransactionId,Cashier_Time,Preparation_Time)
VALUES(#Storeid, #TransTime, #Cashier, #Transaction_Type, #TransactionId, #Cashier_Time, #Preparation_Time)";
comm.Parameters.AddWithValue("#Storeid", rs["StoreId"]);
comm.Parameters.AddWithValue("#TransTime", rs["TransTime"]);
comm.Parameters.AddWithValue("#Cashier", rs["Cashier"]);
comm.Parameters.AddWithValue("#Transaction_Type", rs["Transaction_Type"]);
comm.Parameters.AddWithValue("#TransactionId", rs["TransactionId"]);
comm.Parameters.AddWithValue("#Cashier_Time", rs["Cashier_Time"]);
comm.Parameters.AddWithValue("#Preparation_Time", rs["Preparation_Time"]);
comm.ExecuteNonQuery();
cnn.Close();
}
}
sqlconn.Close();
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
Thank you.
I suppose if all you wanted was a way to test and make sure a connection string is valid and that you can connect to the server and to the database, you could use a method like this:
public bool IsConnectionStringValid(string cs)
{
try
{
using (MySqlConnection conn = new MySqlConnection(cs))
{
conn.Open();
return true;
}
}
catch
{
return false;
}
}
Although I have to admit, in all my years of developing in C#, I've never used anything like this. Normally, as people have said in the comments, you already know before runtime that your connection string is valid and working.
I would like to find a way to exit out of datareader after the if statement so that I can execute the insert query in else statement. Is there a way to do it?
I am getting the error that dr is still open and hence cannot perform the below query.
sVendorDetails.VendorID = insertcmd.ExecuteNonQuery();
Here is the code:
public class VendorDetails
{
int _VendorID;
string _VendorName;
public int VendorID
{
set { _VendorID = value; }
get { return _VendorID; }
}
public string VendorName
{
set { _VendorName = value; }
get { return _VendorName; }
}
}
public VendorDetails VendorCheck(string sVendorName)
{
SqlCommand cmd = new SqlCommand("dbo.usp_GetVendorByVendorName", myConnection);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#VendorName", SqlDbType.VarChar));
cmd.Parameters["#VendorName"].Value = sVendorName;
VendorDetails sVendorDetails = null;
try
{
myConnection.Open();
SqlDataReader dr = cmd.ExecuteReader();
if (dr.HasRows)
{
while (dr.Read())
{
sVendorDetails = new VendorDetails();
sVendorDetails.VendorID = ((int)dr["VendorID"]);
sVendorDetails.VendorName = ((string)dr["VendorName"]).ToUpper().Trim();
}
}
else if (dr.HasRows!= true)
{
ClientScript.RegisterStartupScript(this.GetType(), "alert", "alert('VendorName:" + sVendorName + " not found. Inserting Vendor details into Vendor and Invoice table.')", true);
SqlCommand insertcmd = new SqlCommand("dbo.InsertVendorName", myConnection);
insertcmd.CommandType = CommandType.StoredProcedure;
insertcmd.Parameters.Add(new SqlParameter("#VendorName", SqlDbType.VarChar));
insertcmd.Parameters["#VendorName"].Value = sVendorName;
sVendorDetails = new VendorDetails();
sVendorDetails.VendorID = insertcmd.ExecuteNonQuery();
sVendorDetails.VendorName = sVendorName;
}
dr.Close();
return sVendorDetails;
}
catch (SqlException err)
{
throw new ApplicationException("DB usp_GetVendorByVendorName Error: " + err.Message);
}
finally
{
myConnection.Close();
}
}
You will need to close/dispose of your DataReader prior to reusing the connection, as it's still being used.
Maybe something like this?
var readerHasRows = false;
using (var dr = cmd.ExecuteReader())
{
readerHasRows = dr.HasRows;
if(readerHasRows)
{
while (dr.Read())
{
sVendorDetails = new VendorDetails();
sVendorDetails.VendorID = ((int)dr["VendorID"]);
sVendorDetails.VendorName = ((string)dr["VendorName"]).ToUpper().Trim();
}
}
}
if(!readerHasRows)
{
ClientScript.RegisterStartupScript(this.GetType(), "alert", "alert('VendorName:" + sVendorName + " not found. Inserting Vendor details into Vendor and Invoice table.')", true);
SqlCommand insertcmd = new SqlCommand("dbo.InsertVendorName", myConnection);
insertcmd.CommandType = CommandType.StoredProcedure;
insertcmd.Parameters.Add(new SqlParameter("#VendorName", SqlDbType.VarChar));
insertcmd.Parameters["#VendorName"].Value = sVendorName;
sVendorDetails = new VendorDetails();
VendorDetails.VendorID = insertcmd.ExecuteNonQuery();
sVendorDetails.VendorName = sVendorName;
}
There are a few things I would like to mention
Your main issue is that you are not closing your DataReader. You can use the using statement for it
You don't need to explicitly open and close the SqlConnection. The SqlCommand object will do it as needed.
You don't need to check with if (dr.HasRows) and then check again in while (dr.Read()). Also, you don't need to loop to pick up only one row of data.
Ideally, I would put the "Fetch" part in a separate function and the "insert" in a separate function, so the functions stay small and reusable.
Your pattern is superfluous if (flag) {TakeAction();} else if (!flag) {TakeAction2();}. Every time the code hits theelse, it will also hit theif (!flag)`
sVendorDetails.VendorID = insertcmd.ExecuteNonQuery(); line looks fishy. If your Stored Procedure returns the VendorId, then you should use ExecuteScalar. Currently it is just storing 1 in all case since you are presumably inserting one row.
Don't discard the original SqlException when creating a custom ApplicationException. Upstream system might want to know more details than you are passing. Pass it along as the InnerException
I have also changed some stylistic aspects:
The variable names changed to the more commonly used camelCase, instead of the incorrectly used Hungarian Notation (sVendorDetails instead of oVendorDetails)
Brace in K&R style
Used var when the right side is a new statement
Use Object Initializers instead of creation+assignment
Below is the code
public VendorDetails VendorCheck(string vendorName, SqlConnection myConnection) {
try {
return GetVendor(vendorName, myConnection) ?? InsertVendor(vendorName, myConnection);
} catch (SqlException err) {
throw new ApplicationException("DB usp_GetVendorByVendorName Error: " + err.Message, err);
}
}
VendorDetails GetVendor(string vendorName, SqlConnection myConnection) {
using (var cmd = new SqlCommand("dbo.usp_GetVendorByVendorName", myConnection)) {
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#VendorName", SqlDbType.VarChar));
cmd.Parameters["#VendorName"].Value = vendorName;
using (SqlDataReader dr = cmd.ExecuteReader()) {
ClientScript.RegisterStartupScript(this.GetType(), "alert", "alert('VendorName:" + vendorName + " not found. Inserting Vendor details into Vendor and Invoice table.')", true); // TODO: Does this really belong here!?!?
if (dr.Read()) {
return new VendorDetails {
VendorID = ((int)dr["VendorID"]),
VendorName = ((string)dr["VendorName"]).ToUpper().Trim()
};
}
}
}
return null;
}
VendorDetails InsertVendor(string vendorName, SqlConnection myConnection) {
using (var insertcmd = new SqlCommand("dbo.InsertVendorName", myConnection)) {
insertcmd.CommandType = CommandType.StoredProcedure;
insertcmd.Parameters.Add(new SqlParameter("#VendorName", SqlDbType.VarChar));
insertcmd.Parameters["#VendorName"].Value = vendorName;
return new VendorDetails {
VendorID = (int)insertcmd.ExecuteScalar(),
VendorName = vendorName
};
}
}
I'm updating some old legacy code and I ran into a problem with the
SqlCommand.ExecuteReader() method. The problem is that it's not returning any
results. However, using SqlDataAdapter.Fill(), I get results back from the
database. What am I doing wrong? How can I get results back using the data
reader?
var connectionString = ConfigurationManager.ConnectionStrings["MyConnectionString"].ToString();
using (var sqlConnection = new SqlConnection(connectionString))
{
using (var sqlCommand = new SqlCommand())
{
sqlCommand.Connection = sqlConnection;
sqlCommand.CommandType = CommandType.Text;
sqlCommand.CommandText = "SELECT * FROM MyTable WHERE ID = 1";
sqlConnection.Open();
// This code works.
//var dataTable = new DataTable();
//using (var sqlDataAdapter = new SqlDataAdapter(sqlCommand))
//{
// sqlDataAdapter.Fill(dataTable);
//}
// This code is not working.
using (var sqlDataReader = sqlCommand.ExecuteReader())
{
while (sqlDataReader.Read())
{
// This fails because the data reader has no results.
var id = sqlDataReader.GetInt32(0);
}
}
}
}
Could it be that there is no Int32 in your results ?
var id = sqlDataReader.GetInt32(0); // <-- this might not be an Int32
Either try:
var id = sqlDataReader.GetValue(0);
Or cast to the correct type (BIGINT for example is Int64), not sure without seeing your data.
Try this..
var id = 0;
using (var sqlDataReader = sqlCommand.ExecuteReader())
{
while (sqlDataReader.Read())
{
id = sqlDataReader.GetInt32(sqlDataReader.GetOrdinal("ColName"));
}
}
I have moved the variable outside of the reader code or the variable will only be accessible inside that scope. I would avoid specifying the ordinal in the code, in case someone altered the columns in the DB.
Also, specify the columns in the SQL statement... SELECT ColName FROM ... and use params in the query
If you got to that line then it has results
Does not mean the value is not null
And you should not use a SELECT *
If may have a problem with an implicit cast
Try Int32
try
{
if(sqlDataReader.IsDBNull(0))
{
// deal with null
}
else
{
Int32 id = sqlDataReader.GetInt32(0);
}
}
catch (SQLexception Ex)
{
Debug.WriteLine(Ex.message);
}
var connectionString = ConfigurationManager.ConnectionStrings["MyConnectionString"].ToString();
using (var sqlConnection = new SqlConnection(connectionString))
{
sqlConnection.Open();
string sql = "SELECT * FROM MyTable WHERE ID = 1";
using (var sqlCommand = new SqlCommand(sql, sqlConnection))
{
using (var sqlDataReader = sqlCommand.ExecuteReader())
{
while (sqlDataReader.Read())
{
// This fails because the data reader has no results.
var id = sqlDataReader.GetInt32(0);
}
}
}
}
When I run my code on debug I get this error:
Conversion failed when converting from a string to a uniqueidentifier
Here is the code:
public class UserObject
{
private string m_name = string.Empty;
public UserObject(string id)
{
#region Internal Logic
try
{
using (SqlConnection cn = new SqlConnection(SiteConfig.ConnectionString))
{
string sSQL = "SELECT [UserName] FROM [aspnet_users] WHERE [UserID] = #UserID";
using (SqlCommand cm = new SqlCommand(sSQL, cn))
{
cm.Parameters.AddWithValue("#UserID", id);
cn.Open();
using (SqlDataReader rd = cm.ExecuteReader())
{
while (rd.Read())
{
m_name = rd[0].ToString();
}
rd.Close();
}
cn.Close();
}
}
}
catch (Exception ex)
{
}
#endregion Internal logic
}
}
You said in your comment to the question that id does not have a value when being passed into the method. From the database point of view, uniqueidentifiers can be null (DBNull in C#), but to achieve this, you'd have to leave out the parameter or set DBNull.Value explicitly.
In C#, Guid can not be null - so you must either provide Guid.Empty or a string that can be converted to a Guid in the call to AddWithValue.
EDIT
Sample code follows: Please note that given the SQL statement you use, you won't get any results for the Guid.Empty case unless you have a user the ID of which contains only 0s. I suggest, you change the where clause of your SQL statement as follows:
WHERE [UserId] = ISNULL(#UserID, [UserId])
That way, you get all users when you pass null.
public UserObject(string id)
{
try
{
using (SqlConnection cn = new SqlConnection(SiteConfig.ConnectionString))
{
string sSQL = "SELECT [UserName] FROM [aspnet_users] WHERE [UserID] = #UserID";
using (SqlCommand cm = new SqlCommand(sSQL, cn))
{
if (id.Length == 0)
cm.Parameters.AddWithValue("#UserID", Guid.Empty);
else if (id == null)
cm.Parameters.AddWithValue("#UserID", DBNull.Value);
else
cm.Parameters.AddWithValue("#UserID", Guid.Parse(id));
cn.Open();
using (SqlDataReader rd = cm.ExecuteReader())
{
while (rd.Read())
{
m_name = rd[0].ToString();
}
rd.Close();
}
cn.Close();
}
}
}
catch (Exception ex)
{
}