Decimal.Parse Issue - c#

I have a problem with decimal parse, I know this question been asked a loot, but none of the solution worked for me, and i've been stuck in here for two days now.
My problem is my CultureInfo is set to fr_Fr and when i put the code below an error shows caused with comma that separates decimal instead of period.
double entree = Convert.ToDouble(row["entree"]);
double sortie = Convert.ToDouble(row["sortie"]);
int id_mw = Convert.ToInt32(row["mouvment_w_id"]);
qte_Stock += entree - sortie;
decimal qte_s ;
MessageBox.Show("" + CultureInfo.CurrentCulture);
qte_s = Decimal.Parse(Convert.ToString(qte_Stock), NumberStyles.Number ^ NumberStyles.AllowThousands);
MessageBox.Show("" + qte_s);
qte.CommandText = "Update tcpos.dbo.Warehouse_mouvement set qte_stock= " + qte_s + " where mouvment_w_id = "+id_mw;
qte.ExecuteNonQuery();

What's the type of qte_Stock
...
it was a decimal
...
Then you have your answer since you want to make it a decimal.
Pass the decimal as Parameter to prevent sql-injection and this issue(decimal separator).
For example(assuming SQL-Server as rdbms):
using(var con = new SqlConnection(connectionString))
using(var cmd = new SqlCommand("Update tcpos.dbo.Warehouse_mouvement set qte_stock=#qte_stock where mouvment_w_id = #mouvment_w_id", con))
{
cmd.Parameters.AddWithValue("#qte_stock", qte_stock);
cmd.Parameters.AddWithValue("#mouvment_w_id", id_mw);
con.Open();
cmd.ExecuteNonQuery();
}

qte_s = qte_Stock.ToString ("#.#", System.Globalization.CultureInfo.InvariantCulture);
This will solve, if your problem is because in your culture (like mine), the comma seaparates decimals, and not thousands.
Also, use parameterized SQL, like Damien_The_Unbeliever and Jonh Skeet said.

Related

Datetime includes 't' for time gives an Error in c# when inserting

My web api list contains a datetime field which includes the following format
"2018-09-17T09:35:01.5842031 05:30" but it should be "2018-09-17 09:35" however, Processtime is datetime Column and this column values automatically converts to "2018-09-17T09:35:01.5842031 05:30" though I send it as datetime field
How do I accomplish this task when inserting the value.
Insert query is like this
foreach (var item in talleyheaderlist)
{
SQL = "insert into TalleySheetHeader (Processtime) values (#ProcessStartTime)";
SqlCommand com = new SqlCommand(SQL, con);
com.Parameters.AddWithValue("#ProcessStartTime", item._TsStartTime );
con.Open();
com.ExecuteNonQuery();
con.Close();
}
and i use C# code to insert to SQL server 2014 DB
parameter Insertion
com.Parameters.AddWithValue("#ProcessStartTime", item.ProcessStartTime);
I appreciate somebody's help...
"my...list contains a datetime field which includes the Following format "2018-09-17T09:35:01.5842031 05:30""
Let me stop you there. The quoted value is a string representation of a value. That string might have come from a DateTime or (given that 05:30 could be a TimeZone) a DateTimeOffset, but it isn't that type any more.
You need to stop using AddWithValue, because (as it explains on that page) when you do...
com.Parameters.AddWithValue("Processtime", item._TsStartTime );
and
com.Parameters.AddWithValue("#TalleyProcessStartTime", _valstartedtiem);
(both of which come from your answer to your question) both variables are strings, but your SQL wants that parameter to be a datetime, so you're letting/forcing SQL to make that conversion for you.
So you either need to get the original value (before it became a string), or convert the string back to a DateTime, using DateTime.Parse, probably using the overload with DateTimeStyles, using the RoundTripKind. Although that ISO format should have a plus or minus for the TimeZone; but it might work.
Now that you have a datetime, explicitly pass it as a SqlDbType.DateTime, as shown on the AddWithValue link article. Now you can remove the convert(...,121) from the Sql, since the parameter is now the correct type.
Bonus tips: SqlConnection and SqlCommand are both IDisposable so each should be in a using block. Once you've done that, you don't need to call Close as the implicit Dispose will call it when it exits the using block.
Thanks for every One's help. but i found the answer after a while.
basically ths datetime format is in ISO 8601 format in that case, I had to convert it as follows,
foreach (var item in talleyheaderlist)
{
SQL = "insert into TalleySheetHeader (Processtime) values convert(char(22),#Processtime,121)"; SqlCommand com = new SqlCommand(SQL, con); com.Parameters.AddWithValue("Processtime", item._TsStartTime );
con.Open();
com.ExecuteNonQuery();
con.Close();
}
and to seperately split the date & time to remove 't' and then re-join
string[] Separate = item._TsStartTime.Split(' ');
string a = Separate[0];
string[] _dateTime = a.Split('T');
string _startdate = _dateTime[0];
string _starttime = _dateTime[1];
string _valstartedtiem = _startdate +' ' + _starttime;
com.Parameters.AddWithValue("#TalleyProcessStartTime", _valstartedtiem);
however , there may be other easy Solutions but so far this worked for me. if there is any easy Solution Please do share.
You can simply do this:
string dateTime = "2018-09-17T09:35:01.5842031 0530";
var date = DateTimeOffset.ParseExact(dateTime.Replace(' ','-'), "yyyy-MM-dd'T'HH:mm:ss.fffffffzzz", CultureInfo.InvariantCulture);
More on how 'T' and 'z' works is here:
http://support.sas.com/documentation/cdl/en/lrdict/64316/HTML/default/viewer.htm#a003169814.htm
Please insert following logic in your global.asax.cs file
protected void Application_BeginRequest(Object sender, EventArgs e)
{
CultureInfo newCulture = (CultureInfo)System.Threading.Thread.CurrentThread.CurrentCulture.Clone();
newCulture.DateTimeFormat.ShortDatePattern = "your date format";
newCulture.DateTimeFormat.DateSeparator = "/";
Thread.CurrentThread.CurrentCulture = newCulture;
//ModelBinders.Binders.Add(typeof(DateTime), new DateTimeModelBinder());
}

name variable from oracle sql string value in c#

This is my first project in c#. I have a little experience in Access VBA. I would like to move my apps over to be stand alone programs. I'm querying a table that has training types and dates. I would like to compare some of the types of training against each other based on the dates they were performed. The three training types are RWT010, RWP000, and RWT010BP. If RWT010BP exists and is newer it is the only one I need. Otherwise I need RWT010 and RWP000. I have figured out how to load the values into variables, but I need to be able to work with them. I would like the name of the dateTime value to be the trainType for the same row. That way I can compare them and output the right combination.
My old Access logic looked like this:
LABEL_DATE: IIf(IsNull([RWT010]),"RWT010BP: " & _
Format([RWT010BP],"Short Date"),IIf([RWT010BP]>[RWT010],"RWT010BP: " & _
Format([RWT010BP],"Short Date"),"RWT010: " & _
Format([RWT010],"Short Date") & " & " & "RWP000: " & _
Format([RWP000],"Short Date")))
This is how far I've gotten in c#:
Console.Write("Enter ID: ");
int idnum = Convert.ToInt32(Console.ReadLine());
string sql = "SELECT EXPID, TYPE, DATE_LATEST FROM TRAINING_TABLE where expid =" + idnum;
OracleCommand cmd = new OracleCommand();
cmd.Connection = conn;
cmd.CommandText = sql;
using (DbDataReader reader = cmd.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
int expid = reader.GetInt32(0);
string trainType = reader.GetString(1);
DateTime trainDate = reader.GetDateTime(2);
It looks like the original Access logic has one DB row with three date fields, [RWT010], [RWT010BP], and [RWP000]. But in Oracle that's been normalized so you're getting back multiple rows, each of which has a a datetime field named [DATE_LATEST], and then name field called [TYPE] that's equal to "RWT010", "RWT010BP", or "RWP000".
And you were thinking, you want to handle those RWP000 date values by name, just like in Access. You were right, that's the clearest way to do it, and I'll show you how. I misunderstood what you were asking.
One way to do this would be to write an Oracle stored procedure that duplicates the Access logic. That's not the question you asked, but it's a legitimate way to do it. However, it would be more complicated than the Access version due to the change in the database, and anyway I haven't written Oracle SQL in years and I don't have an Oracle server handy to give me arbitrary, cryptic syntax errors about semicolons and whitespace.
So what I'm going to do is write a loop in C# to grab the datetimes from the DB rows and put them in local variables, and then duplicate the Access logic in C# using those variables instead of fields. It'll be a little verbose compared to the Access version, but sometimes that's how it goes.
int idnum = Convert.ToInt32(Console.ReadLine());
string sql = "SELECT EXPID, TYPE, DATE_LATEST FROM TRAINING_TABLE where expid =" + idnum;
// I don't know how you're using this so I'll just declare it here
// and leave that to you.
String dateLabel = "";
OracleCommand cmd = new OracleCommand();
cmd.Connection = conn;
cmd.CommandText = sql;
using (DbDataReader reader = cmd.ExecuteReader())
{
DateTime? RWT010 = null;
DateTime? RWT010BP = null;
DateTime? RWP000 = null;
// No need to check reader.HasRows. If it has no rows, reader.Read()
// will return false the first time, that's all.
while (reader.Read())
{
// Doesn't look to me like expid is used
//int expid = reader.GetInt32(0);
string trainType = reader.GetString(1);
DateTime trainDate = reader.GetDateTime(2);
switch (trainType) {
case "RWT010":
RWT010 = trainDate;
break;
case "RWT010BP":
RWT010BP = trainDate;
break;
case "RWP000":
RWP000 = trainDate;
break;
}
}
if (RWT010 == null || RWT010BP > RWT010) {
dateLabel = String.Format("RWT010BP: {0:d}", RWT010BP);
} else {
dateLabel = String.Format("RWT010: {0:d} & RWP000: {1:d}", RWT010, RWP000);
}
}
The original logic was this:
If RWT010 isn't null,
Do A
Otherwise, if RWT010BP > RWT010
ALSO do A
But if none of the above,
Do B
The first two branches do the exact same thing, so we can condense them both into one branch.
"Don't Repeat Yourself", as they say. You don't want to return to this code a year from now, wonder if those two lines were required to be the same, and then guess wrong or else not notice that they are the same, and only change one or the other. It's just a mess.
If you're not familiar with String.Format(), there's a lot to it. In the first argument string, {0} means "insert the second argument here"; {1} means "insert the third", and so on. The ":d" inside the curly braces is optional; it means to pass "d" as format information to the value its inserting. DateTime will interpret that "d" to mean "Short Date". You could also do it like this:
dateLabel = String.Format("RWT010BP: {0}", RWT010BP.Value.ToShortDateString());
Or like this:
dateLabel = "RWT010BP: " + RWT010BP.Value.ToShortDateString();
I have to use RWT010BP.Value in that line instead of just RWT010BP because RWT010BP is declared with a ? after it. That makes it a "nullable" value. A regular DateTime can't be null, but we need to accommodate nulls here.
If you're using C#6, you can do it like this, which I prefer. I didn't use it above because I don't know what version of C# you're on. Always prefer the least amount of "noise" cluttering up the code.
dateLabel = $"RWT010BP: {RWT010BP:d}";
That's the same ":d" as in String.Format("{0:d}", ...) above.
One more thing: idnum is an int, but don't ever concatenate a string value into a SQL string. That's a massive security vulnerability and people here will (rightly, I'm afraid) give you a very hard time for even contemplating it.
Use OracleCommand.Parameters instead, as shown in this answer. I would have used that even in this case, personally, just as a conditioned reflex.

How could I compute the number from the database and show it to the Label everytime I change the combo box value?

I have a database values that I have to show to the label as the person salay per hour.
My code is here:
sqc = con.CreateCommand();
string query5 = "SELECT [SalaryGrade] FROM tbl_gradestep where GradeNumber =" + cmbGradeNumber.SelectedItem.ToString() + " and StepNumber =" + cmbStepNumber.SelectedItem.ToString() + "";
sqc.CommandText = query5;
sda = new SqlDataAdapter(sqc);
dt = new DataSet();
sda.Fill(dt);
if(dt.Tables[0].Rows.Count > 0)
{
lblSalary.Text = dt.Tables[0].Rows[0]["SalaryGrade"].ToString();
lblHour.Text = (dt.Tables[0].Rows[0]["SalaryGrade"].ToString()/22/8);
}
con.Close();
The computation is database values divided by 22 then divide it again by 8.
This is, quite explicitly, a string:
dt.Tables[0].Rows[0]["SalaryGrade"].ToString()
A string is just text. You don't perform math on it. If this string is guaranteed to be an integer, you can convert it directly:
lblHour.Text = (int.Parse(dt.Tables[0].Rows[0]["SalaryGrade"])/22/8);
If it's not guaranteed, then you might want some error checking first:
int salaryGrade;
if (!int.TryParse(dt.Tables[0].Rows[0]["SalaryGrade"], out salaryGrade))
{
// wasn't an integer, handle the error condition here
}
lblHour.Text = (salaryGrade/22/8);
Note: Integer division is going to result only in an integer. If you're looking for decimal values, you're going to want to convert your numbers to something with decimal precision. (Such as decimal, which also has .Parse() and .TryParse() methods of course.) Otherwise you may just end up with zeroes and not know why.
the error is "Operator "/" cannot be applied to operands of type
"string" and "int"
The error message is pretty informative. The following
dt.Tables[0].Rows[0]["SalaryGrade"].ToString()
is a string and 22 is an int literal. You can't apply the division operator to them. How could you divide a string with an int, it is a meaningless operation. That you need is something like the following:
((decimal)dt.Tables[0].Rows[0]["SalaryGrade"])/(22*8)
First you cast the SalaryGrade to a decimal and then you divide this with the hours.
Note: In the above line I have assumed that SalaryGrade can be casted to a decimal. If the cast is not possible an exception would be thrown. So a more safe approach it would be to try to use the TryParse method of decimal:
decimal salaryGrade;
if(decimal.TryParse(dt.Tables[0].Rows[0]["SalaryGrade"], out salaryGrade))
{
var salaryPerHour = salaryGrade/(22*8);
}
The error occurs because you cannot use a math operation in a string!
Try this: declare an int variable and assign to it the data from the table and then use the int in the "label.Text" assign converting that int to string.
Hope helped ya!
Thank you guys for helping me out here. I read all your answers then modify my code and boom. Works like a charm.
decimal salaryGrade;
sqc = con.CreateCommand();
string query5 = "SELECT [SalaryGrade] FROM tbl_gradestep where GradeNumber =" + cmbGradeNumber.SelectedItem.ToString() + " and StepNumber =" + cmbStepNumber.SelectedItem.ToString() + "";
sqc.CommandText = query5;
sda = new SqlDataAdapter(sqc);
dt = new DataSet();
sda.Fill(dt);
if(dt.Tables[0].Rows.Count > 0)
{
lblSalary.Text = dt.Tables[0].Rows[0]["SalaryGrade"].ToString();
if (decimal.TryParse(dt.Tables[0].Rows[0]["SalaryGrade"].ToString(), out salaryGrade))
{
}
lblHour.Text = Convert.ToDecimal(salaryGrade / 22 / 8).ToString("0.00");
}
con.Close();
}

How to convert double value into string value

I want to convert a double value into a string value, but when I am concatenating this string(double) value, it is changing the . to , and I can't manipulate this value. I tried to use String.Replace but didn't work too.
What I can do in this case. Here is my Code.
object[] campos = new object[1];
campos[0] = (double)56.25566;
Parameters[1] = "gdinvdllo005.start.load.coleta.o(" + campos[0].ToString() + ")";
It sounds like your thread has a culture which uses "," as the decimal separator. The simplest approach is probably to call string.Format specifying the invariant culture:
Parameters[1] = string.Format(
CultureInfo.InvariantCulture,
"gdinvdllo005.start.load.coleta.o({0})",
campos[0]);
It seems that your current culture uses a comma as decimal separator but you want to force a point. Then you can use NumberFormatInfo.InvariantInfo in double.ToString:
double doubleValue = 56.25566;
string stringValue = doubleValue.ToString(NumberFormatInfo.InvariantInfo);
Parameters[1] = "gdinvdllo005.start.load.coleta.o(" + stringValue + ")";

InvalidCastException in Npgsql

My question is:I want to write the result by suming a column which is money type between two dates.
Code:
using (NpgsqlConnection b = new NpgsqlConnection("Server=127.0.0.1;Port=5432;User Id=postgres;Password=xxxxxxxx;DataBase=deneme;"))
{
try
{
b.Open();
NpgsqlCommand c = new NpgsqlCommand("SELECT SUM(tutar) FROM market where tarih between '" + dateTimePicker1.Value + "' and '" + dateTimePicker2.Value + "'", b);
double toplam = ((double)c.ExecuteScalar());
b.Close();
b.Dispose();
MessageBox.Show(toplam.ToString("n"));
}
Try casting to decimal instead of double.
The Postgres documentation for the "money" type suggests that the output is in the form "$1,000.00" (locale-dependent), in which case you'd need to parse the return value and remove the punctuation before casting.
Also, if that's production code, you'll want to parameterize your SQL instead of appending parameter values in there, otherwise you're open to potential SQL injection attacks and may have performance problems as well.
There are a few threads discussing currency data types in .NET which might also be helpful. Here's one: Does anyone know of a money type in .NET?

Categories

Resources