ExecuteReader not returning anything - c#

I have a table called 'MatchType' and it contains:
ID | MatchTypeName
1 | One Day
2 | Two Day
3 | T20
I have a method to retrieve a record from that table based on a sting that will match a value in MatchTypeName:
public static int GetByName(string matchType)
{
MatchType item = new MatchType();
using (SqlConnection con = new SqlConnection(BaseDataAccessLayer.GetConnectionStringByName()))
{
using (SqlCommand cmd = new SqlCommand(STORED_PROC_GetByName, con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#matchTypeName", SqlDbType.VarChar, 20).Value = matchType;
con.Open();
using (IDataReader reader = cmd.ExecuteReader())
{
item.LoadFromReader(reader);
}
}
}
return item.Id;
}
This method calls this stored procedure:
CREATE PROCEDURE [dbo].[MatchType_GetByName]
(#matchTypeName varchar(20))
AS
BEGIN
SET NOCOUNT ON
SELECT
[Id], [MatchTypeName]
FROM
[dbo].[MatchType]
WHERE
[MatchTypeName] = #matchTypeName
RETURN ##ERROR
END
When calling the GetByName method I am passing in a string "One Day". I have confirmed this through debugging. I can't post an error message that is helpful as there isn't one being generated. Just no data is being returned in the reader...
I have a couple of other methods and stored procedures that use a similar process and they work. The only thing that I can see is the difference is that I am using the WHERE clause on a varchar/string value which is something that the other queries don't do...
Yet i can run this stored proc and it returns all the records..
BEGIN
SET NOCOUNT ON
SELECT
[Id],
[MatchTypeName]
FROM
[dbo].[MatchType]
RETURN ##ERROR
END

The default length for varchar declared without size is 1. You declared it like that in your stored proc parameter so you're only passing the first character.
Change your declaration:
(#matchTypeName varchar)
to a relevant size:
(#matchTypeName varchar(20))
Also, add the size in the code and make sure that the case in your parameter name matches your stored proc:
cmd.Parameters.Add("#matchTypeName", SqlDbType.VarChar, 20).Value = matchType;

The procedure is running the query and showing the results (which is why it works in SSMS), but doesn't actually return anything. Try this (note, I haven't actually tested it).
CREATE PROCEDURE [dbo].[MatchType_GetByName]
#matchTypeName varchar(20),
#matchTypeID INT OUTPUT
AS
BEGIN
SET NOCOUNT ON
SELECT
#matchTypeID = [Id], [MatchTypeName]
FROM
[dbo].[MatchType]
WHERE
[MatchTypeName] = #matchTypeName
RETURN ##ERROR
END

Try this:
using (SqlCommand cmd = new SqlCommand(STORED_PROC_GetByName, con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#matchTypeName", matchType);
con.Open();
using (IDataReader reader = cmd.ExecuteReader())
{
item.LoadFromReader(reader);
}
}
SqlCommand.Parameters Property

Related

MySQLDataReader not reading C#

The Stored Procedure:
BEGIN
SELECT * FROM `user` WHERE `EmailAddress`= #p0 AND `Password` = #p1;
END
Where #p0 and #p1 are Varchar(100).
And the code:
using (MySqlConnection con = new MySqlConnection(Database.MySQLConstring))
{
using (MySqlCommand cmd = new MySqlCommand("LoginCheck", con))
{
cmd.CommandType = CommandType.StoredProcedure; //"LoginCheck"
cmd.Parameters.AddWithValue("email", Email);
cmd.Parameters.AddWithValue("password", Pword);
con.Open();
MySqlDataReader reader = cmd.ExecuteReader();
UserModel UM = new UserModel();
While (reader.Read())
{
UM.UserId = (int)reader["UserID"];
UM.DisplayName = (string)reader["DisplayName"];
UM.Moderator = (int)reader["Moderator"];
}
con.Close();
While(!string.IsNullOrEmpty(UM.DisplayName) && UM.UserId != 0)
{
Result = 1;
return UM;
}
Result = -1;
return UM;
}
}
The code runs succesfull until it comes to the while(reader.Read()) part, then it skips it and goes to the con.close(). No errors or exceptions are thrown. It worked when I was using it when everything was SQL and not MySQL ,but I need to get it working in MySQL.
When I run the stored Procedure itself in de databse then I get my result that I need. but when I use the code it will skip the While part of the code.
If I were going to execute a procedure that was declared as:
CREATE PROCEDURE x(em VARCHAR, pw VARCHAR) --declaration of parameters
BEGIN
SELECT * FROM `user` WHERE `EmailAddress`= em AND `Password` = pw;
END
I would ensure the parameters in my C# code were named the same as in the declaration of the stored procedure:
cmd.Parameters.Add(new MySqlParameter("em", Email));
cmd.Parameters.Add(new MySqlParameter("pw", Password));
I suspect that your query is not getting any rows, because the values you set never make it into the parameters, and are hence never used to query. reader.Read() returns false, because there are no rows. Also make sure that the values for EMail and Password that you're querying really do exist in the table
Try as a debugging thing, to make your query like:
SELECT UserID, DisplayName, Moderator FROM `user` WHERE `EmailAddress`= #p0 AND `Password` = #p1
UNION ALL
SELECT 0, CONCAT_WS(' ', 'There is no user with email/password of', #p0, '/', #p1), '' FROM DUAL;
Or however your parameters are named now..
Your reader.Read()should now return true because this query should always return a row, so inspect the value of DisplayName, it should tell what search terms were applied

Why is The C# code not returning a value from Stored Procedure

I am trying to pull one piece of data from my database using a Stored Procedure that looks like this.
USE [PSD]
GO
/****** Object: StoredProcedure [dbo].[ocso_GetNextDTEventNumber] Script Date: 1/19/2017 10:12:19 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[ocso_GetNextDTEventNumber]
#EventNumber varchar(15) OUTPUT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
--increment last number by 1
UPDATE LU_EVENT_NUMBERS SET evn_last_number = evn_last_number + 1 where evn_year = Year(GetDate())
--return event number to caller
--Get the next event number for all incidents
SELECT #EventNumber = evn_comp_formatted_next_num from LU_EVENT_NUMBERS where evn_year = Year(GetDate())
END
I test this procedure using this SQL Code
DECLARE #NewEventNumber varchar(15)
Execute dbo.ocso_GetNextDTEventNumber
#EventNumber = #NewEventNumber OUTPUT;
Print convert(varchar(15),#NewEventNumber)
And I get the results I would expect. Now when I try to get the results in my C# code which looks like this:
public string GetEventNumber(string enumber)
{
string results;
SqlConnection _con = new SqlConnection();
_con.ConnectionString =
"Data Source=ops-devsql;" +
"Initial Catalog=PSD;" +
"User id=****;" +
"Password=****;";
_con.Open();
{
using (SqlCommand _cmd = new SqlCommand("ocso_GetNextDTEventNumber", _con))
{
_cmd.Parameters.Add("#NewEventNumber", SqlDbType.VarChar, 15)
.Direction = ParameterDirection.Output;
_cmd.ExecuteNonQuery();
results = _cmd.Parameters["#NewEventNumber"].Value.ToString();
//results = (string)_cmd.Parameters["#NewEventNumber"].Value.ToString();
return results;
}
}
}
I get an empty string back. Why is this not working?
You have forgotten to tell the command that you want to execute a stored-procedure:
using (SqlCommand _cmd = new SqlCommand("ocso_GetNextDTEventNumber", _con))
{
_cmd.CommandType = CommandType.StoredProcedure;
//...
}
If you don't specify it the default is taken which is Text(so a plain sql query). I guess you have somewhere an empty Try....Catch because this should cause an exception.
You should also use the same parameter name:
_cmd.Parameters.Add("#EventNumber", SqlDbType.VarChar, 15).Direction = ParameterDirection.Output;
_cmd.ExecuteNonQuery();
results = _cmd.Parameters["#EventNumber"].Value.ToString();

Return ID if record exist, else Insert and return ID

I have the below C# code to check if the record does not exist, insert and return id. But also I need if the record exists, it return the value. What change should I make to C# and SQL part for this to happen? Database is sQL server. Do I still have to use ExecuteScalar() for this?
con.Open();
// Insert ClinRefFileTypeMaster
string command1 = string.Format(
"if NOT exists (select * from [ClinRefFileTypeMaster] where [ClinRefTypeName] = '{0}') Insert into [ClinRefFileTypeMaster] ([ClinRefTypeName]) output INSERTED.[ClinRefTypeID] VALUES('{0}')",
dataToParse[i][0]
);
SqlCommand ClinRefFileTypeMaster = new SqlCommand(command1, con);
// check if there is an value
object checkValue = ClinRefFileTypeMaster.ExecuteScalar();
if (checkValue != null)
ClinRefFileTypeId = (int)checkValue;
A stored procedure to do all the stuff for you would look something like.....
CREATE PROCEDURE usp_Get_ClinRefTypeID
#ClinRefTypeName VARCHAR(100),
#ClinRefTypeID INT OUTPUT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #NewID TABLE(ClinRefTypeID INT);
SELECT #ClinRefTypeID = [ClinRefTypeID]
FROM [ClinRefFileTypeMaster]
where [ClinRefTypeName] = #ClinRefTypeName;
IF (#ClinRefTypeID IS NULL)
BEGIN
INSERT INTO [ClinRefFileTypeMaster] ([ClinRefTypeName])
OUTPUT inserted.[ClinRefTypeID] INTO #NewID(ClinRefTypeID)
VALUES(#ClinRefTypeName)
SELECT #ClinRefTypeID = [ClinRefTypeID] FROM #NewID
END
END
And your C# code would look something like.....
con.Open();
// Insert ClinRefFileTypeMaster
SqlCommand cmd = new SqlCommand("usp_Get_ClinRefTypeID", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#ClinRefTypeID", SqlDbType.Int).Direction = ParameterDirection.Output;
cmd.Parameters.Add(new SqlParameter("#ClinRefTypeName", dataToParse));
// get the value back from the output parameter
cmd.ExecuteNonQuery();
int ClinRefTypeName = Convert.ToInt32(cmd.Parameters["#ClinRefTypeID"].Value);
There are many ways to achieve this. 1) You can do it all in inline Sql 2) you can do it all in stored proc. 3) You can do it all in code but split the code as this code is frankly doing too much. In general I would avoid insert/query in the same method.
Also try to use SqlParameters instead of building the query as string concat.
I would propose something like this which makes the code a bit more readable
public int InsertAndRetrieveClientRefId(string clientRefTypeName)
{
int id = GetIdIfRecordExists(clientRefTypeName);
if (id == 0)
{
// insert logic here
id = GetIdIfRecordExists(clientRefTypeName);
}
return id;
}
public int GetIdIfRecordExists(string clientRefTypeName)
{
int id = 0;
string command = "select id from ClinRefFileTypeMaster where ClinRefTypeName = #ClinRefTypeName";
SqlParameter nameParameter = new SqlParameter("#ClinRefTypeName", System.Data.SqlDbType.NVarChar, 10) { Value = clientRefTypeName };
using (SqlConnection connection = new SqlConnection("ConnectionString"))
{
using (SqlCommand cmd = new SqlCommand(command))
{
cmd.Parameters.Add(newParameter);
connection.Open();
cmd.Connection = connection;
int.TryParse(cmd.ExecuteScalar().ToString(), out id);
}
}
return id;
}
do all this in database i.e in store procedure
if not exists (select 1 from [ClinRefFileTypeMaster] where [ClinRefTypeName] =#name)
begin
Insert into [ClinRefFileTypeMaster] ([ClinRefTypeName]) values (#name)
end
else
begin
select (as desired) from ClinRefFileTypeMaster where where [ClinRefTypeName] =#name
end
this will either insert new record or it will select already inserted information
Youll need to add an IF EXISTS clause to the SQL statement as well, checking for the same conditions, and providing logic to return a value.
It seems using ExecuteReader would be better if you need it to return the value from the database.
2¢
I personally would split the logic into two queries and run the If statement within c# checking if the value is in the database, then updating the database else returning a value from the database
conn.open()
int CheckDb;
String Command1 = "select * from [ClinRefFileTypeMaster] where [ClinRefTypeName] = #ClinRefFileTypeId";
using (SqlCommand ClinRefFileTypeMaster = new SqlCommand(command1, con);
{
cmd.Parameters.AddWithValue("#ClinRefFileTypeId", {0});
CheckDb = (int)ClinRefFileTypeMaster.ExecuteScalar();
}
If (CheckDb != 0)
//Logic for returning the value from the database
Else
//Here you can request user check data or insert the value into the database.
if you want to perform Instert operation, I think its better you call a stored procedure and write your query in the procedure. It will be safer.
SqlCommand command = new SqlCommand("procedureName",con);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue(“#value1”, txtValue1.Text);
command.Parameters.AddWithValue(“#value2”, Value2);
int value = command.ExecuteScalar();
IF EXISTS (SELECT 1 FROM Table WHERE FieldValue='')
BEGIN
SELECT TableID FROM Table WHERE FieldValue=''
END
ELSE
BEGIN
INSERT INTO TABLE(FieldValue) VALUES('')
SELECT SCOPE_IDENTITY() AS TableID
END
If you want to pass the querystring, you can call select query and if it returns null perform a insert opeartion and use scope_Identity() to get the ID
INSERT INTO YourTable(val1, val2, val3 ...)
VALUES(#val1, #val2, #val3...);
SELECT SCOPE_IDENTITY();

SQL SERVER 2005 return value

Hi all I have the following stored procedure
#UserName varchar(150),
#UserEmail varchar(300),
#UserPassword varchar(150),
#ContactNumber varchar(150),
#ContactMobile varchar(150),
#AreaOfCountry varchar(150),
#UserId int OUTPUT,
#AllreadyReg int OUTPUT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
--DECLARE #UserId int, #AllreadyReg int
IF (SELECT COUNT(UserId) FROM Users WHERE (UserName = #UserName) OR (UserEmail = #UserEmail)) > 0
BEGIN
SET #UserId = 0
SET #AllreadyReg = 1
END
ELSE
BEGIN
INSERT INTO Users (UserName,UserEmail,UserPassword,ContactNumber,ContactMobile,AreaOfCountry) VALUES (#UserName,#UserEmail,#UserPassword,#ContactNumber,#ContactMobile,#AreaOfCountry)
SELECT #UserId = SCOPE_IDENTITY()
SET #AllreadyReg = 0
END
however when I use it using c# and asp.net its not returning anything, however when I just execute it it does have a results #UserId and #AllreadyReg but the return value is 0 and a single field.
my c# code is below but it never has any rows
using (SqlConnection con = new SqlConnection(connectionString))
{
Response.Write("Line 61");
using (SqlCommand cmd = new SqlCommand("spR_Register", con))
{
Response.Write("line 64");
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#UserName", TxtUsername.Text.Trim());
cmd.Parameters.AddWithValue("#UserEmail", TxtEmail.Text.Trim());
cmd.Parameters.AddWithValue("#UserPassword", TxtPassword.Text.Trim());
cmd.Parameters.AddWithValue("#ContactNumber", TxtPhone.Text);
cmd.Parameters.AddWithValue("#ContactMobile", TxtMobile.Text);
cmd.Parameters.AddWithValue("#AreaOfCountry", TxtAreaOfCountry.SelectedValue);
cmd.Parameters.AddWithValue("#UserId", ParameterDirection.Output);
cmd.Parameters.AddWithValue("#AllreadyReg", ParameterDirection.Output);
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
if (reader.HasRows)
{
Response.Write("line 78");
etc etc
can anyone help
thanks
With the edit: the mistake is using ExecuteReader on a command that doesn't select a data grid - that should be done with ExecuteNonQuery.
The important thing here is how the parameter is added. For example:
var alreadyReg = cmd.CreateParameter();
alreadyReg.Direction = System.Data.ParameterDirection.Output;
alreadyReg.ParameterName = "AllreadyReg";
alreadyReg.DbType = DbType.Int32;
cmd.Parameters.Add(alreadyReg);
//...
cmd.ExecuteNonQuery();
//...
int val = (int)alreadyReg.Value;
Depending on the type of DbCommand object, there may be an overload that accepts all of these in one line - the above assumes just DbCommand. With SqlCommand, you can simplify a bit:
var alreadyReg = cmd.Parameters.Add("AllreadyReg", SqlDbType.Int);
alreadyReg.Direction = ParameterDirection.Output;
//...
cmd.ExecuteNonQuery();
//...
int val = (int)alreadyReg.Value
You might have already handled it, but just in case, make sure to specify direction of parameter in c# code.
Here
cmd.Parameters.AddWithValue("#UserId", ParameterDirection.Output);
wrong usage of AddWithValue. The second parameter is parsed as parameter value, not direction type. Use proper parameter contructor and the add the result to collection.

Command.ExecuteScalar always return null while Stored Procedure in Management Studio runs fine

I have the following SQL stored procedure with one input parameter and one out parameter.
CREATE PROCEDURE [dbo].[spCanUserEdit]
(
#username nvarchar(255)
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #CanEdit bit
SELECT
#CanEdit = CanUserEdit
FROM tblUsers
WHERE username = LOWER(#username)
RETURN SELECT #CanEdit
END
GO
In the stored procedure above CanUserEdit column in tblUsers is bit type column and with default value to 0. Now when I execute this procedure in Management Studio it runs fine but when i use command.ExecuteScalar() in my C# code, it always returns null. Could anyone please tell me what I am doing wrong here.
Following is my C# method
public static bool CanUserEdit(string userName)
{
using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings[Constants.ConnectionStringName].ConnectionString))
{
using (SqlCommand cmd = new SqlCommand())
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "spCanUserEdit";
cmd.Connection = conn;
cmd.Parameters.Add(new SqlParameter("#username", userName));
conn.Open();
bool canEdit = (bool)cmd.ExecuteScalar();
return canEdit;
}
}
}
The problem is in the way you return data. If you want to use ExecuteScalar, you should not RETURN but instead simply SELECT.
Try to change the SP as following:
CREATE PROCEDURE [dbo].[spCanUserEdit]
(
#username nvarchar(255)
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #CanEdit bit
SELECT
#CanEdit = CanUserEdit
FROM tblUsers
WHERE username = LOWER(#username)
SELECT #CanEdit
RETURN 0
END
GO
If you can't change the SP, but the code, the solution is to read parameter '#ReturnValue' with ExecuteNonQuery.
Use a scaler function instead of a stored procedure. SQL functions are much easier to setup and they return a scaler value by default so no 'OUTPUT' or return variable declarations necessary. Example:
CREATE FUNCTION [dbo].[ScalerFnExample]()
RETURNS VARCHAR(50)
AS
BEGIN
RETURN (SELECT TOP 1 Thing FROM Examples.dbo.Stuff)
END
C# Example:
public string SqlScalerFnExample()
{
string retVal = default;
try
{
using (SqlConnection sqlConnection = new SqlConnection("Server=127.0.0.1;Database=Examples;Trusted_Connection=True;"))
{
SqlCommand userFn = new SqlCommand("SELECT dbo.ScalerFnExample()", sqlConnection);
sqlConnection.Open();
retVal = (string)userFn.ExecuteScalar();
}
}
catch (Exception ex)
{
Console.WriteLine($"SqlScalerFnExample() - Exception: {ex.Message}");
}
return retVal;
}

Categories

Resources