How can I resolve this error an c# - c#

I want to insert data into a database table:
myCommand.CommandText = "INSERT INTO Selectionner (IdPrestation,
IdPhrase, DegreUrgence,RisqueConcerne,rowguid,Cotation) " +
"VALUES ('" +new Guid(emp.IdPrestation) +
"', '" +new Guid(emp.IdPhrase)+ "', '" +
emp.DegreUrgence + "','" + emp.RisqueConcerne + "','" +
new Guid(emp.rowguid) + "','" + emp.Cotation + "')";
But this returns an error:
Guid should contain 32 digits with 4 dashes
(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).
How can I resolve this error ?

One or many of your
emp.IdPrestation //Or
emp.IdPhrase //Or
emp.rowguid //Check them before creating
is/are not a GUID. That is why it is throwing an error.
EDIT: starts
How to use Guid.TryParse() which returns true if the parse operation was successful; otherwise, false.
//How to parse safely
Guid IdPrestation;
Guid IdPhrase;
Guid rowguid;
if(Guid.TryParse(emp.IdPrestation, out IdPrestation) &&
Guid.TryParse(emp.IdPhrase, out IdPhrase) &&
Guid.TryParse(emp.rowguid, out rowguid) )
{
//all variables have been parse successfully
//Execute the sql query as follows using parameters
}
EDIT: ends
Also, passing parameters as direct string with inline sql is an unsafe bad practice. Instead use a parameterised query.
myCommand.CommandText = "INSERT INTO yourTableName (c1, c2, ...)
VALUES (#p1, #p2,...)";
myCommand.Parameters.Add(new SqlParameter("p1", valueforCol1));
myCommand.Parameters.Add(new SqlParameter("p2", valueforCol2));
...

Try to use a parameterised query as a first improvement.
Then, try to use Guid.Parse(string s) instead of new Guid(string s). That way, i expect that an exception will be raised for the strings that are not compliant.
The constructor might be a little to permissive, and in this case you would want to fail-fast so that you know what field is giving you trouble.

You cannot create GUID simply from a string ,the string needs to be guid compliant
Guid originalGuid = Guid.NewGuid();
originalGuid.ToString("B") gets converted to {81a130d2-502f-4cf1-a376-63edeb000e9f}
Similarly
"N" - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx (32 digits)
"D" - xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx (32 digits separated by hyphens)
"B" - {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} (same as "D" with addition of braces)
"P" - (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) (same as "D" with addition of parentheses)
"X" - {0x00000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00.0x00}}
The guid itself has no format. It is just a value. Note, that you can create guids using NewGuid or using the guid's constructor. Using NewGuid, you have no control over the value of the guid. Using the guid's constructor, you can control the value. Using the constructor is useful if you already have a string representation of a guid (maybe you read it from a database) or if you want to make it easier to interpret a guid during development. You can also use the Parse, ParseExact, TryParse, and TryParseExact methods.
So, you can create guids like this:
Guid g1 = Guid.NewGuid(); //Get a Guid without any control over the contents
Guid g2 = new Guid(new string('A',32)); //Get a Guid where all digits == 'A'
Guid g3 = Guid.Parse(g1.ToString());
Guid g4 = Guid.ParseExact(g1.ToString("D"),"D");
Guid g5;
bool b1 = Guid.TryParse(g1.ToString(), out g5);
Guid g6;
bool b2 = Guid.TryParseExact(g1.ToString("D"),"D", out g6);

Related

How to get number value with Decimal from DataReader

According to the SQL queries below, I need to get a number value 2083.10, but when try to use the code to get int value from dbreader, it will be only 2083. the demical were gone.
string SQLCash = #"SELECT sum(t2.Cash-Change) AS Cash
FROM dbFBHdr t1, dbFBCollection t2
WHERE t1.Branch = t2.Branch
AND t1.CashNo = t2.CashNo
AND t1.CashDate >= '" + PDC.DateFrom + "' " +
"AND t1.CashDate <= '" + PDC.DateTo + "' " +
"AND t1.Status = 'CLOSED'";
FbCommand cmdCASH = new FbCommand(SQLCash, FbCon);
cmdCASH.ExecuteNonQuery();
FbDataReader readerCASH = cmdCASH.ExecuteReader();
while (readerCASH.Read() == true)
{
if (readerCASH["Cash"].ToString() == "")
{
PDC.CASH = "0";
}
else
{
PDC.CASH += String.Format("{0:n}",readerCASH["Cash"]);
PDC.TOCASH = readerCASH.GetInt32(readerCASH.GetOrdinal("Cash"));
}
}
And This is the code which I use it to get Int value from SQL
PDC.TOCASH = readerCASH.GetInt32(readerCASH.GetOrdinal("Cash"));
Since you need to Gets the value as a Decimal object, You need to use SqlDataReader.GetDecimal(Int32) method instead:
readerCASH.GetDecimal(readerCASH.GetOrdinal("Cash"));
Because the GetInt32 method will get the value as a 32-bit signed integer. Also you need to change the TOCASH's type to decimal. Also you should always use parameterized queries to avoid SQL Injection. Something like this:
AND t1.CashDate >= #DateFrom
yourCommand.Parameters.AddWithValue("#DateFrom", PDC.DateFrom);
//And other parameters also
Although specify the type directly and use the Value property is better than AddWithValue. See this https://blogs.msmvps.com/jcoehoorn/blog/2014/05/12/can-we-stop-using-addwithvalue-already/
Don't use GetInt32 if you want to get value as decimal, use GetDecimal
PDC.TOCASH = readerCASH.GetDecimal(readerCASH.GetOrdinal("Cash"));
You are formatting it to be without commas so it will be return as it is integer
PDC.CASH += String.Format("{0:n2}",readerCASH["Cash"]);
n2 means 2 digits after comma also i suggest you to use {0:c2} if you are working with currency
If you not sure to which .Net type will be mapped initial RDBMS one (e.g. Number(16, 4) -> ? will it be Single, Double or Decimal?) you can try converting:
decimal result = Convert.ToDecimal(readerCASH["Cash"]);

C# timestamp zero value can't read in my reader

I'm having problem in getting the updated timestamp value which is returning 0000-00-00 00:00:00. My reader cannot read the data it gives an error saying Invalid DateTime.
I want to get only the time under TimeIn and TimeOut fields.
This is my code:
try
{
SQLConn.sqL = "SELECT * FROM tblinformation WHERE " + search + " LIKE '" + strSearch + "%'";
SQLConn.ConnDB();
SQLConn.cmd = new MySqlCommand(SQLConn.sqL, SQLConn.conn);
SQLConn.dr = SQLConn.cmd.ExecuteReader();
ListViewItem x = null;
listView2.Items.Clear();
while (SQLConn.dr.Read() == true)
{
x = new ListViewItem(SQLConn.dr["AttendanceNo"].ToString());
x.SubItems.Add(SQLConn.dr["RFIDNo"].ToString());
x.SubItems.Add(SQLConn.dr["IDNumber"].ToString());
x.SubItems.Add(SQLConn.dr["FullName"].ToString());
x.SubItems.Add(SQLConn.dr["Designation"].ToString());
x.SubItems.Add(DateTime.Parse(SQLConn.dr["TimeIn"].ToString()).ToShortTimeString());
x.SubItems.Add(DateTime.Parse(SQLConn.dr["TimeOut"].ToString()).ToShortTimeString());
x.SubItems.Add(SQLConn.dr["VPlateNo"].ToString());
listView2.Items.Add(x);
}
}
catch (Exception ex)
{
Interaction.MsgBox(ex.ToString());
}
finally
{
SQLConn.cmd.Dispose();
SQLConn.conn.Close();
}
The MySql provider for ADO.Net retrieves MySql Timestamp columns as .Net DateTime objects. You do not want to call SQLConn.dr["TimeIn"].ToString(), especially when you're just gonna try to Parse() it again. The object in the reader field is already a DateTime value, so you can just do this:
x.SubItems.Add( ((DateTime)SQLConn.dr["TimeIn"]).ToShortTimeString() );
That will perform way better and be much less prone to errors. I'm not 100% certain it will fix the issue in the question, but it will certainly make debugging easier, especially if you separate it to two lines like this:
DateTime temp = (DateTime)SQLConn.dr["TimeIn"];
x.SubItems.Add( temp.ToShortTimeString() );
Now you can put a break point on the first line and check the actual value in the debugger.
While I'm here, I can't say strongly enough how BAD this is:
SQLConn.sqL = "SELECT * FROM tblinformation WHERE " + search + " LIKE '" + strSearch + "%'";
This is the kind of code where you find out one morning you were hacked six months ago.
Don't do it.
You need query parameters, like this:
SQLConn.cmd = new MySqlCommand("SELECT * FROM tblinformation WHERE column LIKE #search + '%';", SQLConn.conn);
SQLConn.Parameters.Add("#search", MySqlDbType.VarChar, 50).Value = strSearch;
Even internal-only apps need to work this way. As a bonus, it also tends to perform faster, and can help with many DateTime and numeric formatting issues, since you work with native .Net types for the parameter values.
MySQL Server allows an "invalid" DATETIME value 0000-00-00 00:00:00 to be stored (as long as the NO_ZERO_DATE server mode isn't set).
Since this isn't a valid .NET DateTime value, you need to add AllowZeroDateTime=true to your connection string, which will cause Connector/NET to return all DATETIME columns as the special MySqlDateTime type.
Alternatively, if you still want to use .NET's DateTime struct instead of MySqlDateTime, you can specify ConvertZeroDateTime=true in your connection string, which will convert 0000-00-00 00:00:00 to DateTime.MinValue when retrieving it from the database.
However, you should carefully check all your database insertion code to make sure you're not inserting invalid date/time values that MySQL Server is silently converting to 0000-00-00. You should also use STRICT mode if at all possible, to avoid silent data loss.

Trying to check if int value is indeed an int

I'm trying to check a passed variable to ensure that it is indeed of type Int. However, I keep having an error appear that tells me that the variable "year" cannot be converted from an int to a string. I'm stuck because I'm not trying to convert it over so I'm confused as to what I'm missing.
[HttpGet("[action]")]
[Authorize]
public ListResult ProblemsYTD(int year = "")
{
var sql = "SELECT DatePart(yyyy, CLL.Call_Log_Date) as [ProblemsYear], CLL.Service as [Service], Sum((DATEDIFF(dd, CLL.Call_Log_Date, GetDate()))) as [DaysOpen] " +
"FROM VMWareSM_Test.dbo.RV_CALL as CLL " +
"Where CLL.IPK_Stream_Ref = '19' And DatePart(yyyy, CLL.Call_Log_Date)";
int myInt;
if (!int.TryParse(year, out myInt))
{
year = "%" + year + "%";
sql += " = #year";
}
sql += " Group by CLL.Service, DatePart(yyyy, CLL.Call_Log_Date) "+
"Order by CLL.Service DESC; ";
SqlParameter[] sqlParams =
{
new SqlParameter
{
ParameterName = "#year",
Value = year,
DbType = DbType.Int32,
Direction = ParameterDirection.Input
}
};
Let's start from your use of the variable year. It is used as part of a where condition where also a DatePart function call is involved. Now DataPart returns an integer so you need an integer for your checks, not a string.
At this point your declaration of the method should be simple an integer without a default value or you could use a default value of zero.
You cannot use an empty string as default value for an integer. C# doesn't allow this free implicit conversions between types like an Option Strictless VB.NET
So the call should be simply
public ListResult ProblemsYTD(int year = 0)
at this point all the code that checks if the caller has passed an integer is useless because the caller cannot pass any other kind of type or value. Just integers or types that can be cast to an integer without loosing information (byte, short but not long) You declare the method to receive an integer and the compiler blocks any different type with a compilation error.
However you could add a check for a reasonable value for your year variable.
For example you could limit the upper and lower values with something like this
if (year >= 2000 && year <= DateTime.Today.Year)
{
sql += " = #year";
}
Note that you cannot concatenate a "%" symbol to an integer for the same reason that you cannot assign an empty string to an integer.
Your function should be declared like this
public ListResult ProblemsYTD(string year = "")
{
...
}
also year = "%" + year + "%";
make no since the % is used in LIKE statements
should be something like this :
if (int.TryParse(year, out myInt))
{
sql += " = #" + year;
}
else
{
throw new Exception("Year is not in correct format");
}
This line looks fishy:
public ListResult ProblemsYTD(int year = "")
You're providing an empty string ("") as the default value for year. I think you mean to have the parameter be a string when it is passed in.
public ListResult ProblemsYTD(string year = "")
I'm trying to check a passed variable to ensure that it is indeed of type Int.
Most likely you just need to use a Route Constraint
Example Route:
routes.MapRoute(
"Product",
"Product/{productId}",
new {controller="Product", action="Details"}
);
Controller:
public class ProductController : Controller
{
public ActionResult Details(int productId)
{
return View();
}
}
with the following producing an error:
/Product/blah
/Product/apple
You can add a route constraint to only route to the controller/action if it is an int:
routes.MapRoute(
"Product",
"Product/{productId}",
new {controller="Product", action="Details"},
new {productId = #"\d+" }
);
This means that your controller is not in charge of type checking (it probably shouldn't anyway) and you can create a another route to catch non-ints and display a different view accordingly.
int year = ""
You cannot set an integer variable to a string value.

Concatenating a char with an int and a string does odd things

I was coding and needed to build up a file name. I wanted to separate the parts of the file names by an _.
I figured that since I only wanted to add on char in I could use '_'.
int id = 125;
string testWithChar = id + '_' + "Something";
Console.WriteLine(testWithChar);
But when I do I get this:
220Something
Kind of odd.
But if I do it right:
int id = 125;
string testWithString = id + "_" + "Something";
Console.WriteLine(testWithString);
I get the expected output:
125_Something
But I am curious. What is really happening in the first one to give me a different number?
The reason is, C# is considering the char as it's unicode value, and thus the addition between them does not add strings, but integers.
_ in ascii is 95, and thus
int id = 125;
string testWithChar = id + '_' + "Something";
is the equivallent of:
string testWithChar = 125 + 95 + "Something";
In contrast, when you add "_", the addition is done between a string and an integer - and the operator just appends the string to it.
The int value of a char is its place in the ASCII table. '_' is at place 95
When you add an integer to another numeric type, you end up with the result of the addition, rather than the concatenation. In this case, char is a numeric value, so 125 + 95 (value of '_') concatenated with your string gives you 220_Something.
I'd create the string as string.Format("{0}_{1}", id, "Something") instead, particularly as your final string gets more complicated.
The int value is replaced with its ASCII value of 95.
Using string formatting is the most safe way:
Console.WriteLine("{0}_Something", id);

Data type mismatch in criteria expression when Query Access DB

I'm having an issue inserting a row into my access db. I keep getting a "Data type mismatch in criteria expression". I've tried tons of different formatted queries and can't seem to figure out where I'm going wrong.
public void addUserToDB(string username)
{
string updateStr = "Insert Into Users ([Username], [Currency], [Joined], [Online], [Notes]) "
+ "Values ( ?, '0', ?, 'Yes', '')";
OleDbCommand update = new OleDbCommand(updateStr, con);
update.Parameters.Add("", OleDbType.VarChar).Value = username;
update.Parameters.AddWithValue("","'#" + DateTime.Now.ToString("G") + "#'");
update.Parameters.AddWithValue("","'#" + DateTime.Now.ToString("G") + "#'");
execute(update);
}
It's not my connection string or anything else since all my other queries work just fine. It has to be something in here. I'm assuming is may have something to due with the date time.
Access DB:
Username: ShortText
Currency: Number
Joined: Date/Time in "General Date" Format
Online: Yes/No
Notes: ShortText
Since your Currency column is Number and Online seems Yes/No (It stores 1 bit), you don't need to use single quotes with them. Using single quotes threat them as a character.
string updateStr = "Insert Into Users ([Username], [Currency], [Joined], [Online], [Notes]) "
+ "Values ( ?, 0, ?, Yes, '')";
^^^ ^^^
And your Joined is DateTime, you shouldn't try to insert string representation of your DateTime.Now. Just insert it as a DateTime as ODBC canonical date format.
From documentation;
Date values must be either delimited according to the ODBC canonical
date format or delimited by the datetime delimiter ("#"). Otherwise,
Microsoft Access will treat the value as an arithmetic expression and
will not raise a warning or error.

Categories