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.
Related
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"]);
If I have an ActionResult method like so:
public ActionResult AllSummaries(int? page, DateTime? yesterday)
Instead of the route being like:
http://serverName/projectName/controllerName/AllSummaries?yesterday=04/03/2017
I would like it to be:
http://serverName/projectName/controllerName/AllSummaries/04/03/2017
So on top of the ActionResult, how do I add a constraint to make the datetime only show the date in format MM/dd/yyyy?
[Route("allsummaries/yesterday/{yesterday:}")]
public ActionResult AllSummaries(int? page, DateTime? yesterday)
I do not need to validate against whether or not the date and day are 1 digit or 2 digit.. it will always be 2 digit.
Any help is appreciated.
UPDATE
Now getting 404 errors:
Here is the link that I am using:
http://serverName/projectName/controllerName/allsummaries/yesterday/3/4/2017
Here is my action:
[Route("controllerName/allsummaries/yesterday/{month?}/{day?}/{year?}")]
[ValidateInput(false)]
public ActionResult AllSummaries(int? page, int? day, int? month, int? year)
{
if (day.HasValue && month.HasValue && year.HasValue)
{
var yesterday = new DateTime(year.Value, month.Value, day.Value);
}
The route that I am generating is from a console application that is going to send out emails automatically via windows service, so I can't use #Url.Action...etc.. I am hardcoding the link like so:
mail.Body = mail.Body + "<div>" + "<p>" +
"http://serverName/projectName/controllerName/allsummaries/yesterday/" +
DateTime.Today.AddDays(-1).Day +
"/" + DateTime.Today.AddDays(-1).Month + "/" +
DateTime.Today.AddDays(-1).Year + "</p>" + "</div>";
The issue is the slashes in the date, which will be interpreted as path separators. The routing framework only parses params between path separators, unless you use the greedy param syntax, i.e. {*yesterday}. However, if you do that any further portions of the URL path will be consumed. For example, if a user changed the URL to something like allsummaries/yesterday/04/03/2017/foo, then 04/03/2017/foo would be passed in as yesterday and your action explodes.
You have two options.
You can use a different date format, like ISO: yyyy-MM-dd, which would make your URL /allsummaries/yesteday/2017-04-03, and you could capture the date portion with a single param: {yesterday}.
[Route("allsummaries/yesterday/{yesterday}")]
You can break up the date components and then recompose them into a DateTime in the action:
[Route("allsummaries/yesterday/{month?}/{day?}/{year?}")]
Then, in your action:
public ActionResult AllSummaries(int? page, int? month, int? day, int? year)
{
var yesterday = DateTime.Today.AddDays(-1); // default
if (month.HasValue && day.HasValue && year.HasValue)
{
yesterday = new DateTime(year.Value, month.Value, day.Value);
}
EDIT
I didn't want to confuse the main issue, but if you choose to follow the second option, breaking up the date into components, there is an issue you'll need to be aware of. If you have an explicit URL like /allsummaries/yesterday/04/03/2017, the modelbinder will be able to parse the "04" and "03" into ints. However, if you try to create the URL, using something like Url.Action, Url.RouteUrl, etc., you will need to feed the params values like "04", rather than an int, or you'll end up with URLs like /allsummaries/yesterday/4/3/2017. You could do that via something like:
#Url.Action("AllSummaries", new
{
month = date.ToString("MM"),
day = date.ToString("dd"),
year = date.Year
})
In other words, you would need to use ToString to get the two digit value, rather than date.Month or date.Day directly.
You should also probably protect the URL a little from tampering, by adding a regex contraint to these params:
[Route("allsummaries/yesterday/{month?:regex([0-9]{2})}/{day?:regex([0-9]{2})}/{year?:regex([0-9]{4}}")]
You can parse day, month and year alone,
and then create the date.
Your code will be like this:
[Route("allsummaries/yesterday/{day}/{month}/{year}")]
public ActionResult AllSummaries(int? page, int day, int month, int year)
{
var yesterday = new Date(day, month, year);
}
[Route("allsummaries/yesterday")]
public ActionResult AllSumaries(int? page)
{
}
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);
An SQL aggregate function counting number of name enteries in DB.
string cnnStr = ConfigurationManager.ConnectionStrings["LGFConnectionString"].ConnectionString;
string mySQL = "SELECT COUNT(*) FROM " + which.table + " WHERE " + which.column + " = ?pram;";
string value = null;
using (MySqlConnection cnn = new MySqlConnection(cnnStr))
{
using (MySqlCommand cmd = new MySqlCommand(mySQL, cnn))
{
MySqlParameter param = new MySqlParameter("?pram", MySqlDbType.VarChar, 128);
param.Value = which.text;
cmd.Parameters.Add(param);
cnn.Open();
value = cmd.ExecuteScalar() as string;
value = cmd.ExecuteScalar().ToString();
cnn.Close();
}
}
Notice that I have called cmd.ExecuteScalar twice. Interesting part is that the query returns different results.
value = cmd.ExecuteScalar() as string;
doesn't return the correct value. It returns null for both if name is present or missing in the name column.
value = cmd.ExecuteScalar().ToString();
returns correctly. This returns "1" if present and "0" if missing.
In searching the web, I haven't found an understandable explanation.
I have read that if name is missing from name column, then cmd.ExecuteScalar will return null.
What is the difference between:
value = cmd.ExecuteScalar() as string;
value = cmd.ExecuteScalar().ToString();
Thank you,
deDogs
as in docs
The as operator is used to perform conversions between compatible types.
The as operator is like a cast except that it yields null on conversion failure instead of raising an exception
// if cmd.ExecuteScalar() is string then return string
// if not then return null
// this will return null, because cmd.ExecuteScalar() won't return string
// for your code it should return Int32
value = cmd.ExecuteScalar() as string;
ToString() in docs
ToString is the major formatting method in the .NET Framework. It
converts an object to its string representation so that it is suitable
for display. (For information about formatting support in the .NET
Framework, see Formatting Types.)
// return a string that represents the current object
// will return correct value because it casts Int32 value to string value
value = cmd.ExecuteScalar().ToString();
The 'as' keyword will return null if the objects type does not match what you are attempting to cast it to.
What is happening in your case is that the returned object is an int and when you call toString on this, it will give you a string representation of the integer. When you use as against it, it gives you a null.
You are doing two different things above. Let's change your code to the following:
decimal value = cmd.ExecuteScalar();
string str1 = value as string;
string str2 = value.ToString();
str1 will be null because decimal cannot be cast to a string.
str2 will be the value because you can call ToString() on a decimal.
I need to convert a string in the database of patients to a int to create a new patient ID.
In the Hospital database, the patient ID is a STRING, not an integer. It is of the form p99. To create a new ID, I need to take out the p, convert to an integer, add 1, then put a 0 in if the value is less than 10, then add back the p.
I am using Microsoft visual studio and C#.
How would I go about this? Any help would be greatly appreciated!
You can use string.Substring Method and Int32.TryParse method.
String.Substring Method (Int32)
Retrieves a substring from this instance. The substring starts at a
specified character position.
Int32.TryParse Method (String, Int32)
Converts the string representation of a number to its 32-bit signed
integer equivalent. A return value indicates whether the conversion
succeeded.
string patientId = "p99";
int id;
if (Int32.TryParse(patientId.Substring(1), out id))
{
patientId = string.Format("p{0}{1}", id < 10 ? "0" : string.Empty, id);
MessageBox.Show("Patient Id : " + patientId);
}
else
{
MessageBox.Show("Error while retrieving the patient id.");
}
You can use int.Parse() (MSDN) to convert a string to an integer.
You can write a simple routine to do this.
Assuming there is always a leading 'p' you can just do sID = sID.substring(1) to remove the first character.
Then you can use Int ID = Int16.Parse(sID) to convert to an Int (16-bit in this case). If you need 32-bit, use Int32.Parse
then ID++ or ID = ID+1 to increment by one.
Next, you need to convert back to a string with sID = ID.ToString()
Finally, do some string manipulation to test the length, add the leading '0' if length = 1, and the leading 'p'.