Displaying Date (c# winforms) - c#

I have a SQL Table with the following columns:
PROFILE
----------------------------------
Name | DateOfBirth | Address | ID
----------------------------------
| | |
| | |
[Name] is a required field while the ID is an autoincrement column.
The remaining fields are not required.
When it comes to displaying again the information of a user in my form, since the DateOfBirth field is not required I always got this value in my textBox 1900-01-01 00:00:00.000 even if it not supplied upon registration.
What I'm trying to accomplish is to display an empty string inthe textBox if the there's no date of birth.
With my naive way of thinking, I wrote a method where it checks first the DateOfBirth column, if it is null, it will return an empty string, else, return the date of birth as a string ex. txtDateOfBirth.Text = GetDateOfBirth();
but it always return the value `1900-01-01 00:00:00.000' cause the field in the database always inserts this value even the user leaves this field as blank.
Can you please help me... thanks...
I also tried this but still don't work:
SELECT BIRTHDATE = CASE BIRTHDATE
WHEN CAST('1900-01-01' AS DATETIME) THEN ''
ELSE BIRTHDATE END
FROM USER

My psychic debugging skills tell me that you're mistakenly setting the birthdate when you insert the row. A good check for that is to hook up a profiler (one comes with SQL Server, if that's what you're using), and watch what's actually getting inserted when you create a new user.
Check the code that's inserting a new user. If you're using DataSets, for instance, check that you don't have a default constraint set on the Birthdate column (click on the cell in the DataSet designer, and check the Properties grid).
It's also possible that the database itself has a default constraint set on that column, but that feels less likely.

Any reason why you don't want to do this?
string theDate = GetDateOfBirth().ToString();
txtDateOfBirth.Text = theDate == "1900-01-01 00:00:00.000" ? "" : theDate;

I got it already! :)
Here's my original code:
protected void SaveUser()
{
SqlConnection conn = new SqlConnection(connectionString);
conn.Open();
SqlCommand cmd = new SqlCommand("INSERT_USER");
cmd.Parameters.Add(new SqlParameter("#NAME", txtName.Text.Trim()));
cmd.Parameters.Add(new SqlParameter("#ADDRESS", txtAddress.Text.Trim()));
cmd.Parameters.Add(new SqlParameter("#DATEOFBIRTH", txtDateOfBirth.Text.Trim()));
cmd.Connection = conn;
cmd.CommandType = CommandType.StoredProcedure;
cmd.ExecuteNonQuery();
}
In my original code, even though txtDateofBirth is empty, it will always pass an empty string to the parameter causing the database to insert '1900-01-01 00:00:00.00', not the NULL value. Here's the modified code. I check first if txtDateOfBirth is not empty (assuming the value entered is a valid date) if true, add cmd.Parameters.Add(new SqlParameter("#DATEOFBIRTH", txtDateOfBirth.Text.Trim())); as a parameter to INSERT_USER stored procedure. Else, #DATEOFBIRTH parameter is not being created and passed at all.
protected void SaveUser()
{
SqlConnection conn = new SqlConnection(connectionString);
conn.Open();
SqlCommand cmd = new SqlCommand("INSERT_USER");
cmd.Parameters.Add(new SqlParameter("#NAME", txtName.Text.Trim()));
cmd.Parameters.Add(new SqlParameter("#ADDRESS", txtAddress.Text.Trim()));
if(txtDateOfBirth.Text.Trim() != String.Empty)
{
cmd.Parameters.Add(new SqlParameter("#DATEOFBIRTH", txtDateOfBirth.Text.Trim()));
}
cmd.Connection = conn;
cmd.CommandType = CommandType.StoredProcedure;
cmd.ExecuteNonQuery();
}
SP:
CREATE PROCEDURE [dbo].[INSERT_USER]
(
#NAME AS VARCHAR(25),
#ADDRESS AS VARCHAR(50) = NULL,
#DATEOFBIRTH AS DATETIME = NULL
)
AS
BEGIN
INSERT INTO [USER] ([NAME], ADDRESS, DATEOFBIRTH) VALUES (#NAME, #ADDRESS, #DATEOFBIRTH)
END

Related

Why does rowsAffected return 0 when I have passed parameters for it to use?

I'm trying to insert data into a database using a SQL procedure and an MVC controller. I have the data obtained using a HTML form which is then retrieved by the Create method and added to the parameters of the SQL procedure.
public ActionResult Create([Bind(Include = "UserID,FirstName,Surname,Password,Salt,Phone_Number,Email,IsAdmin")] SaltUsersTable saltUsersTable, FormCollection fc)
{
if (ModelState.IsValid)
{
SqlConnection con = new SqlConnection(#"Connection String");
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "dbo.AddSaltedUser";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = con;
cmd.Parameters.Add("#Password", SqlDbType.NVarChar, 50).Value = Request.Form["Password"];
cmd.Parameters.Add("#FirstName", SqlDbType.NVarChar, 50).Value = Request.Form["FirstName"];
cmd.Parameters.Add("#Surname", SqlDbType.NVarChar, 50).Value = Request.Form["Surname"];
cmd.Parameters.Add("#Email", SqlDbType.NVarChar, 100).Value = Request.Form["Email"];
cmd.Parameters.Add("#PhoneNumber", SqlDbType.NVarChar, 12).Value = Request.Form["PhoneNumber"];
cmd.Parameters.Add("#response", SqlDbType.NVarChar, 250).Direction = ParameterDirection.Output;
if (Request.Form["FirstName"] == "Admin")
{
cmd.Parameters.Add("#IsAdmin", SqlDbType.Bit).Value = 1;
}
else
{
cmd.Parameters.Add("#IsAdmin", SqlDbType.Bit).Value = 0;
}
//Execute the command just established
con.Open();
Int32 rowsAffected = cmd.ExecuteNonQuery();
con.Close();
The code shown above is the Create controller (the connection string I've replaced to be generic)
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[AddSaltedUser]
#FirstName NVARCHAR(50),
#Surname NVARCHAR(50),
#Password NVARCHAR(50),
#PhoneNumber NVARCHAR(12),
#Email NVARCHAR(50),
#IsAdmin BIT,
#response NVARCHAR(250) OUTPUT
AS
BEGIN
SET NOCOUNT ON
DECLARE #salt UNIQUEIDENTIFIER=NEWID()
BEGIN TRY
INSERT INTO dbo.SaltUsersTable (FirstName, Surname , Password, PhoneNumber, Email, IsAdmin)
VALUES(#FirstName, #Surname, HASHBYTES('SHA_512',#Password+CAST(#salt AS NVARCHAR(36))), #PhoneNumber, #Email, #IsAdmin)
SET #response='Success'
END TRY
BEGIN CATCH
SET #response='ERROR'
END CATCH
END
This code is the SQL procedure I wrote which should insert the parameters passed from the MVC controller apart from the salted hash which is done within the procedure.
The issue with this code is that it won't actually insert anything into the database. When I run through the code and have a breakpoint at rowsAffected it shows that it is 0 and I have no idea why. Where am I going wrong in this code?
I should say however that the parameters do exist and the form values are collected properly within the controller as I have gone through it with a debugger.
Could the problem here be the #IsAdmin Parameter?
You're using the datatype SqlDbType.Bit (and the parameter is BIT also) which as far as I'm aware only accepts 0/1/NULL and you're setting the value to true/false. I get that sometimes true/false 0/1 are interchangeable but I'm not sure how C# would pass this and if it's a non issue but it's one thing to check.
Relevant question: DbType equivalent to SqlDbType.Bit
The problem is that you have a SET NOCOUNT ON statement in your stored procedure. From the docs:
Stops the message that shows the count of the number of rows affected by a Transact-SQL statement or stored procedure from being returned as part of the result set.
It does exactly what you told it to do. Comment out that line in the SP and it will return the number of rows affected: 1 in case of a successful insert, 0 if it fails.
As for your rows not inserting...
In your insert you are using HASHBYTES with an invalid algorithm. This results in a null value for all inputs. Try replacing 'SHA_512' in your SP with 'SHA2_512' and it will give you better results.
While this may be responsible for the rows not being inserted, you can't find out with the errors all disabled. TRY...CATCH is generally a bad idea when you're at this point in the code because it suppresses all those handy error messages that might otherwise tell you what went wrong.
I created a test table and uses your code (with the correct hashing algorithm name) and it worked fine for me. I assume that there is a constraint on your table - a unique index on the password field for instance - that is preventing the records from being added.
As a point of interest, you do know that random salt values make this completely unusable right? Even in example code it's better to have your salt represented by an obviously non-production value like 'stand-in the real salt value' or something.

Problems with sending DateTime to SQL Table

I'm writing WinForms code in C# and basically have the following:
DateTime localDate = DateTime.UtcNow;
SqlConnection Conn = new SqlConnection("....[connection info]....");
Conn.Open();
SqlCommand sqlcomm = new SqlCommand("INSERT INTO dbo.Call VALUES(...., #Time,...);", Conn);
sqlcomm.Parameters.Add("#Time", SqlDbType.DateTime);
sqlcomm.Parameters["#Time"].Value = localDate;
Int32 o = sqlcomm.ExecuteNonQuery();
This throws an error of "When converting a string to DateTime, parse the string to take the date before putting each variable into the DateTime object." From what I gather, it thinks the localDate variable is a string but if I write to the console localDate.GetType() it says System.DateTime.
The column for "#Time" in the database is set up to DateTime, so that's not the issue. Any thoughts?
You're almost there. for Sql Server think among these lines
select cast(getdate() as time)
Problem is that in .net there is no such type as time, so you need to adapt
SqlCommand sqlcomm = new SqlCommand(
"INSERT INTO dbo.Call VALUES(...., cast(#Time as time),...);", Conn);
sqlcomm.Parameters.AddWithValue("#Time", localDate);
this is all you should need. Although, I think, you may not even need to add cast as DB engine itself will try cast it. The problem, I think, that you explicitly said your type SqlDbType.DateTime. But if you use AddWithValue, provider will do things for you.
since #Frédéric mentioned TimeSpan, you can try this as well
sqlcomm.Parameters.AddWithValue("#Time", localDate.TimeOfDay);
' and no cast(#Time as time)
The UTC format is not an sql date time format whuch you specified in the parameters.add
In the past I have formatted the utc time to that of yyyy-MM-dd.
Given this table schema:
create table dbo.call_history
(
id int not null identity(1,1) primary key clustered ,
my_date date null ,
my_time time null ,
my_datetime datetime null ,
)
This code works just fine:
using ( SqlConnection conn = new SqlConnection( connectString ) )
using ( SqlCommand cmd = conn.CreateCommand() )
{
cmd.CommandType = CommandType.Text;
cmd.CommandText = #"
insert dbo.call_history ( my_date , my_time , my_datetime )
values ( #pDate , #pDate , #pDate )
select scope_identity()
";
cmd.Parameters.AddWithValue( "#pDate" , DateTime.UtcNow );
conn.Open();
// double downcast required herebecause scope_identity()
// returns numeric(38,0) which gets mapped to decimal
int id = (int)(decimal) cmd.ExecuteScalar() ;
conn.Close();
}

Error "Data too long for column" when executing stored procedure via c# mysql connection

I am writing a C# application that will access a MySQL Database using a stored procedure with 5 parameters:
in startTime varchar(20),
in endTime varchar(20),
in tagID Int,
in FullDay Int,
in iteration Int
that returns 3 variables all integers.
When executing the MySQLCommand I get the error: "Data too long for column 'startTime' at row 41".
Here is my code:
//create command
MySqlCommand cmd = new MySqlCommand("GetArchiveData", connection);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("startTime", startIn);
cmd.Parameters["startTime"].Direction = ParameterDirection.Input;
cmd.Parameters.AddWithValue("endTime", endIn);
cmd.Parameters["endTime"].Direction = ParameterDirection.Input;
cmd.Parameters.AddWithValue("tagID", tagIn);
cmd.Parameters["tagID"].Direction = ParameterDirection.Input;
cmd.Parameters.AddWithValue("FullDay", fdIn);
cmd.Parameters["FullDay"].Direction = ParameterDirection.Input;
cmd.Parameters.AddWithValue("iteration", iterationIn);
cmd.Parameters["iteration"].Direction = ParameterDirection.Input;
if (cmd.Connection.State == ConnectionState.Closed)
{
cmd.Connection.Open();
}
MySqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
TagData tagData = new TagData();
tagData.TagID = tagIn;
tagData.Dsttimestamp = Convert.ToInt32(dr["timestamp"]);
tagData.PvValue = Convert.ToInt32(dr["sp"]);
tagData.PvValue = Convert.ToInt32(dr["pv"]);
tagDataList.Add(tagData);
}
dr.Close();
this.CloseConnection();
return tagDataList;
If anyone knows why this would happen and why the first occurrence would be row 41 it would be greatly appreciated.
UPDATE:
Removing the Single quotations that are required in the MySQL statement in workbench from the strings startIn and endIn has solved that issue. MySQL uses single quotes to define strings where the C# variable is already declared as a string.
It looks like your problem is in the sproc.
Have you looked at the vaklue you are passing in to it?
It just seems the value is too long for the column so looking at what is being passed will let you know for sure.
Inserting value is too long for the column.
Please debug and Check whether u are inserting correct type of data or correct type value for the column.
There is an hard limit on how much data can be stored in a single row of a mysql table, regardless of the number of columns or the individual column length.

Can't find stored procedure parameters in code-behind

The Overview: I've got a dropdown with a list of reports the user can run. In the table that holds this list, I have ReportID, ReportName, SProc and SQLView fields. The idea here is, the user selects a report name, and based on that a specific Stored Procedure will run, and then a specific view will be bound to a datagrid to display the report. For some reports you need to enter a date, for others you don't.
The Code: Here is what I have written;
protected void btnSubmit_OnClick(object sender, EventArgs e)
{
List<ReportData> myReportData = new List<ReportData>();
using (SqlConnection connection1 = new SqlConnection(str2))
{
//Query the Reports table to find the record associated with the selected report
using (SqlCommand cmd = new SqlCommand("SELECT * from tblManagerReports WHERE ReportID = " + cboFilterOption.SelectedValue + "", connection1))
{
connection1.Open();
using (SqlDataReader DT1 = cmd.ExecuteReader())
{
while (DT1.Read())
{
//Read the record into an "array", so you can find the SProc and View names
int MyRptID = Convert.ToInt32(DT1[0]);
string MyRptName = DT1[1].ToString();
string MyRptSproc = DT1[2].ToString();
string MySQLView = DT1[3].ToString();
//Run the Stored Procedure first
SqlConnection connection2 = new SqlConnection(str2);
SqlCommand cmd2 = new SqlCommand("" + MyRptSproc + "", connection2);
//Set up the parameters, if they exist
if (string.IsNullOrEmpty(this.txtStartDate.Text))
{
}
else
{
cmd2.Parameters.Add("#StDate", SqlDbType.Date).Value = txtStartDate.Text;
}
if (string.IsNullOrEmpty(this.txtEndDate.Text))
{
}
else
{
cmd2.Parameters.Add("#EnDate", SqlDbType.Date).Value = txtEndDate.Text;
}
if (MyRptSproc != "")
{
connection2.Open();
cmd2.ExecuteNonQuery();
}
try
{
//Now open the View and bind it to the GridView
string SelectView = "SELECT * FROM " + MySQLView + "";
SqlConnection con = new SqlConnection(str2);
SqlCommand SelectCmd = new SqlCommand(SelectView, con);
SqlDataAdapter SelectAdapter = new SqlDataAdapter(SelectCmd);
//Fill the dataset
DataSet RunReport = new DataSet();
SelectAdapter.Fill(RunReport);
GridView_Reports.DataSource = RunReport;
GridView_Reports.DataBind();
}
catch
{
ScriptManager.RegisterStartupScript(btnSubmit, typeof(Button), "Report Menu", "alert('There is no View associated with this report.\\nPlease contact the developers and let them know of this issue.')", true);
return;
}
}
}
}
}
The Problem: When the code hits the line
cmd2.ExecuteNonQuery();
and there is a start and end date entered, it's telling me "Procedure or function expects parameter '#StDate', which is not supplied." I've stepped through the code and see that cmd2 has 2 parameters, so why isn't the function seeing them?
Additionally, here's the specific stored procedure which is causing the snafu (I've got 2 others that run fine, but neither of them are trying to pass parameters to a stored procedure:
ALTER procedure [dbo].[usp_DailyProc]
#StDate smalldatetime,
#EnDate smalldatetime
AS
BEGIN
IF OBJECT_ID('Temp_DailyProduction') IS NOT NULL
drop table Temp_DailyProduction;
IF OBJECT_ID('Temp_AuditorDailyProduction') IS NOT NULL
drop table Temp_AuditorDailyProduction;
SELECT
[Audit Date],
Auditor,
Count([Doc #]) AS [Claim Count],
Count([Primary Error Code]) AS [Final Error],
SUM(case when [Status]='removed' then 1 else 0 end) as Removed,
SOCNUM
INTO Temp_DailyProc
FROM PreClosed
WHERE (((Get_Next_Status)='Closed' Or (Get_Next_Status)='Panel' Or (Get_Next_Status)='HPanel'))
GROUP BY [Audit Date], Auditor, SOCNUM
HAVING ((([Audit Date]) Between #StDate And #EnDate));
SELECT
TDP.[Audit Date],
TDP.Auditor,
EID.EMPLOYEE AS [Auditor Name],
TDP.[Claim Count],
TDP.[Final Error],
TDP.Removed,
TDP.[Removed]/TDP.[Final Error] AS [Error Removal Ratio],
TDP.SOCNUM
INTO Temp_AuditorDailyProc
FROM Temp_DailyProc TDP
LEFT JOIN PreLookup EID
ON TDP.Auditor = EID.ID_Trim;
drop table Temp_DailyProduction;
END
I think you need to use the AddWithValue method instead of the Add method.
AddWithValue replaces the SqlParameterCollection.Add method that takes
a String and an Object. The overload of Add that takes a string and an
object was deprecated because of possible ambiguity with the
SqlParameterCollection.Add overload that takes a String and a
SqlDbType enumeration value where passing an integer with the string
could be interpreted as being either the parameter value or the
corresponding SqlDbType value. Use AddWithValue whenever you want to
add a parameter by specifying its name and value.
Had another thought, you are passing a string (Text) value as Date parameter. I think you should convert this to a date type. e.g.
cmd2.Parameters.Add("#StDate", SqlDbType.Date).Value = DateTime.Parse(txtStartDate.Text);
A more robust way of doing this would be to use DateTime.TryParseExact.

Scope_Identity not working with GUID on c#

I've been trying to insert some data on a database and at the same time get the identifier.
The identifier type is a Guid.
I already tried some resolutions.
I was searching but I couldn't found any that worked with a Guid in C#.
The last one I tried was like this:
dbAccess db = new dbAccess();
SqlConnection con = db.openConnection();
Guid retVal = Guid.Empty;
try
{
SqlCommand cmd = new SqlCommand(#"insert into Comment(IdDiscussion,UserId,Description,DateTime)
values(#IdDiscussion,#UserId,#description,#dateTime);
set #ret=SCOPE_IDENTITY();", con);
cmd.Parameters.AddWithValue("#IdDiscussion", discussionId);
cmd.Parameters.AddWithValue("#UserId", userId);
cmd.Parameters.AddWithValue("#description", comment);
cmd.Parameters.AddWithValue("#dateTime", dateTime);
SqlParameter retParameter = new SqlParameter("#ret", SqlDbType.UniqueIdentifier);
retParameter.Direction = ParameterDirection.Output;
cmd.Parameters.Add(retParameter);
cmd.ExecuteNonQuery();
retVal = (Guid)retParameter.Value;
}
catch (Exception e)
{
//doesn't really matter
}
db.closeConnection();
return retVal;
In this case I get the following error on executeNonQuery(): "Operand type clash: numeric is incompatible with uniqueidentifier".
Any suggestion that can help?
scope_identity() only returns the last (scoped) identity value - this value datatype has to be numeric.
So unfortunetly only fix that comes to my mind would be something like this:
declare #op table
(
ColGuid uniqueidentifier
)
insert into Comment(IdDiscussion,UserId,Description,DateTime)
output inserted.CommentId -- GUID column
into #op
values (#IdDiscussion,#UserId,#description,#dateTime)
select top 1 o.ColGuid
from #op o
and then in your code:
var guid = (Guid)cmd.ExecuteScalar();
One more mention: this solution should work in SQL Server 2005 and above
I tried to use SCOPE_IDENTITY() to retrieve Guid values, but not worked with me. You can try declare a SQL variable and generate a new guid with the command NEWID() and in the end do a SELECT command in this variable executing ExecuteScalar method on the command object.
DECLARE #Id UNIQUEIDENTIFIER; SET #Id = NEWID();
INSERT INTO [tablename] ([Id], [Field1], [Field2]) VALUES (#Id, #Field1, #Field2);
You must add your parameters on the command normally.
cmd.Parameters.AddWithValue("#Field1", "Field 1 Value");
cmd.Parameters.AddWithValue("#Field2", "Field 2 Value"));
So, execute and retrieve the value.
var obj = cmd.ExecuteScalar();
Guid guid = (Guid)obj;

Categories