Pass two parameters to stored procedure and grab value - c#

First check my controller code below. Then also check the bottom picture which contains my stored procedure code in SQL Server Management Studio.
Now the issue is: my PagedSearchedUserItems procedure needs two int parameters and it will return output of few columns of data (you can see data sample from screen shot picture below).
In my controller, I am not getting idea how I can pass two parameters and get back that data in variable Items. Can you please fix my controller code to pass two parameters correctly, and grab all values on my variable "Items" ?
Controller code:
using (var ctx = new db_demoEntities())
{
var Items = ctx.Database.SqlQuery<SearchedUserItems>("EXEC PagedSearchedUserItems #TakeFrom",2).ToList<SearchedUserItems>();
}
Stored procedure code:
CREATE PROCEDURE PagedSearchedUserItems
#TakeFrom INT,
#TakePerPage INT
AS
BEGIN
SELECT *
FROM SearchedUserItems
ORDER BY Id
OFFSET #TakeFrom ROWS
FETCH NEXT #TakePerPage ROWS ONLY;
END
PagedSearchedUserItems 2,5
SQL Server Management Studio screenshot

I think you are looking for something like that. This code should work fine with passing two parameters. I am assuming that "SearchedUserItems" object is maching your Data model.
using (var ctx = new db_demoEntities())
{
object[] xparams = {
new SqlParameter("#TakeFrom", 2),
new SqlParameter("#TakePerPage", 5)};
var Items = ctx.Database.SqlQuery<SearchedUserItems>("EXEC PagedSearchedUserItems #TakeFrom, #TakePerPage", xparams).ToList<SearchedUserItems>();
}

Related

Problems executing SQL Server Stored Procedures from EFCore

I have a database with several tables, and I have prepared a stored procedure (basically consisting of delete * from ... statements) to delete rows from these tables. When I run the stored procedure from SQL Server Management Studio, it works just fine.
Now, I'd like to execute the same stored procedure from my C# application. I use the below code to do this:
using (var context = new DBContext())
{
var param = new SqlParameter[] {...}; //create parameters here
//trigger the stored procedure for deletion from the first table here
context.Database.ExecuteSqlRaw("[dbo].[delete_first] #id,#date", param);
//trigger the stored procedure for deletion from the hts_clients table here
context.Database.ExecuteSqlRaw("[dbo].[delete_second] #id,#date", param);
}
When executed, the first invocation seems to work fine. However, the second one always throws an exception with the following message:
Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 0, current count = 1. Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 0, current count = 1
(Note: Yes, the exception message appears exactly like this. I didn't paste it twice.)
However, I'm definitely not using any transactions in the bodies of the stored procedures i.e I have no Begin Transaction/Commit Transaction/Rollback Transactions statements anywhere in either of them, nor did I wrap the invocation in a transaction from EFCore (as can be seen from the code segment above). Can anyone tell me why this is happening?
Thanks in advance.
The dbContext is not getting refreshed automatically after executeSql. You have to reload the entry that was changed.
try to use this:
context.Database.ExecuteSqlRaw("[dbo].[delete_first] #id,#date", param);
_context.Entry(...deletionClass... ).Reload();
context.Database.ExecuteSqlRaw("[dbo].[delete_second] #id,#date", param);
//and maybe if you need you can try it again
_context.Entry(...deletionClass... ).Reload();
but in your case maybe easier to create a new DbContext for the second stored procedure.
using (var context1 = new DBContext())
{
var param = new SqlParameter[] {...}; //create parameters here
//trigger the stored procedure for deletion from the first table here
context1.Database.ExecuteSqlRaw("[dbo].[delete_first] #id,#date", param);
}
using (var context2 = new DBContext())
{
var param = new SqlParameter[] {...}; //create parameters here
//trigger the stored procedure for deletion from the hts_clients table here
context2.Database.ExecuteSqlRaw("[dbo].[delete_second] #id,#date", param);
}

Stored Procedure With Array parameters csharp to mssql

This is my manual query work in SQL:
SELECT * FROM Accounts where Phone in ('05763671278','05763271578','04763125578')
how can I get parameter like this to stored procedure from csharp?
I have a phones array in C#. I get this array from parameters from a view (multi check box select). This is my view:
<td><input type="checkbox" class="CheckboxClass" value="'#item.Phones'"/></td>
This is my controller action:
public ActionResult SendSMSOrMail(string[] values){
// this give "'05763671278','05763271578','04763125578'"
string numbers = string.Join(",", values);
// ...
utility.cmd.Parameters.Add("#numbers", numbers);
// ...
}
But the result is null. What is wrong? I want to get result of all records which contain these phones.
There are several ways to do this. The first is to create your array as a string of text, separated by commas or semicolons or some other separator, then in the SQL you would parse that string. That's pretty simple and straight forward, but does not scale very well and there is a limit to the max character length of a parameter.
A second choice is to use an XML parameter. Example here:
https://stackoverflow.com/a/1069388/61164
A third choice is to use a Table parameter, which be passed as a .NET collection.
I don't have an example of that handy. I've done it before, but that should give you enough info to search for yourself.
I suggest you use a table valued parameter
CREATE TYPE PhonesTableType AS TABLE
(
Phone VARCHAR(12)
)
GO
Then you should declare (at the creation script) that you stored procedure expects a parameter of this type:
CREATE PROCEDURE dbo.your_stored_procedure_name
(
#PhonesTableType PhonesTableType READONLY
)
....
SELECT A.*
FROM Accounts AS A
INNER JOIN #PhonesTableType AS P
ON A.Phone = P.Phone
Then at the C# code you should create a DataTable with one column and pass there the values you have mentioned. Last you should pass this a parameter to your stored procedure.
var phonesDataTable = new DataTable("Phones");
phonesDataTable.Columns.Add("Phone", typeof(string));
foreach(var phone in phones) // phones is the values
{
phonesDataTable.Rows.Add(phone);
}
Then if we suppose that you have named command the command that you would ask to be executed, before executing it you should add the above as a parameter:
var sqlParameter = new SqlParameter
{
ParameterName = "#PhonesTableType",
SqlDbType = SqlDbType.Structured,
Value = phonesDataTable
};
command.Parameters.Add(sqlParameter);

Can't get stored procedure results with Entity Framework 6

I have a stored procedure which returns a 0 or a 1 depending on whether or not a specified email address exists in my database:
CREATE PROCEDURE [DatabaseSchema].[EmailAddressIsDuplicate] (#emailAddress nvarchar(255))
AS
BEGIN
SET NOCOUNT ON;
IF EXISTS(
SELECT *
FROM [DatabaseSchema].[EmailUpdatesRegistrant]
WHERE EmailAddress = #emailAddress
)
RETURN 1
ELSE
RETURN 0
RETURN 0
END
GO
And I'm trying to derive the results of this stored procedure from an Entity Framework 6 database context:
using (DatabaseContext dbContext = new DatabaseContext())
{
ObjectParameter param = new ObjectParameter("emailAddress", typeof(bool));
var result = dbContext.EmailAddressIsDuplicate(emailAddress);
}
I'm getting lots of errors.
Error #1: Using the code above, var result is always set to -1.
Error #2: I tried navigated to Edit Function Import and set the Returns a Collection Of to a Boolean scalar value. This throws the following error:
The data reader returned by the store data provider does not have enough columns for the query requested.
Error #3: I went back and set the Edit Function Import return value to None. Then I tried the following code from this answer:
using (DatabaseContext dbContext = new DatabaseContext())
{
var p = new SqlParameter("#emailAddress", emailAddress);
var result = dbContext.Database.SqlQuery<bool>("DatabaseSchema.EmailAddressIsDuplicate", p);
}
No immediate errors thrown, but I have no idea whether or not I can derive useful data from var result. Trying to cast result to bool throws the following error:
Cannot convert type 'System.Data.Entity.Infrastructure.DbRawSqlQuery' to 'bool'
Any ideas on how I can see the results of this stored procedure (0 or 1)?
You could try adding an output parameter (#result) in the stored procedure signature:
CREATE PROCEDURE [DatabaseSchema].[EmailAddressIsDuplicate]
(#emailAddress nvarchar(255), #result bit out)
AS
BEGIN
SET NOCOUNT ON;
IF EXISTS(SELECT *
FROM [DatabaseSchema].[EmailUpdatesRegistrant]
WHERE EmailAddress = #emailAddress)
SET #result = 1
ELSE
SET #result = 0
RETURN #result
END
GO
(you'll have to re-define your EF Model Function definition accordingly)
using (DatabaseContext dbContext = new DatabaseContext())
{
ObjectParameter isDuplicate = new ObjectParameter("isDuplicate", typeof(bool));
var result = dbContext.EmailAddressIsDuplicate(emailAddress, isDuplicate);
bool emailIsDuplicate = (bool)isDuplicate.Value;.
}
If you want to call the stored procedure directly with an out parameter you could follow this suggestion:
Database.SqlQuery calling stored procedure that has multiple output parameters
REASON - The template builder for EF (including v6) incorrectly sets the SP up as returning an INT containing the row count rather than the return value because it incorrectly calls the wrong ObjectContext.ExecuteFunction (found in the template-generated class YourDatabaseEntities that is the child of the DBContext).
Why wrong ExecuteFunction? - The result set incorrectly says the row count of changed rows rather than the return value or output parameters because it calls a different ExecuteFunction that discards the results. The flyover intellisense hint of the ObjectContext.ExecuteFunction says "Executes a stored procedure ….; discards any results returned from the function; and returns the number of rows affected by the execution" rather than the usual "Executes a stored procedure …. with the specified parameters".
WHY -1: I believe the SET NOCOUNT ON is causing the SP to return no count result and that Microsoft's ExecuteFunction returns that as error code.
SP FIXES - 1) You have to comment out SET NOCOUNT ON .
2) You have to change stored procedure to do the SELECT command as last statement instead of the RETURN command.
SOLUTION FIX - 1) After fixing SP, delete SP from Function Imports folder and the Data Store's SP folder. 2) Reload the SP into the EDMX by using the "Update Model from Database" 3) Rebuild all of your data project where the EDMX resides. 4) Exit Visual Studio and return. 5) Rebuild overall solution.
See: Entity Framework (Database first) has incorrect return result from stored procedure
Implement the stored procedure in C# to a value using parameters.
Resource: https://msdn.microsoft.com/en-us/library/yy6y35y8(v=vs.110).aspx
This way, the values can be stored to a variable from the ExecuteReader.
Add the value to model similar to adding a value to a property. The stored procedure could be called from ActionResult. Though this may require adding the stored procedure to a separate layer, that simply runs the stored procedure and adds the value to model afterwards.
try this
CREATE PROCEDURE [DatabaseSchema].[EmailAddressIsDuplicate] (#emailAddress nvarchar(255))
AS
BEGIN
SELECT *
FROM [DatabaseSchema].[EmailUpdatesRegistrant]
WHERE EmailAddress = #emailAddress
SELECT ##ROWCOUNT
END
GO
using (DatabaseContext dbContext = new DatabaseContext())
{
var result = dbContext.Database.SqlQuery<int32>("exec DatabaseSchema.EmailAddressIsDuplicate {0}", emailAddress).FirstOrDefault();
}
Anything other 0 in the return value indicates there is a match and the number indicates the number of matches

Passing a parameter as list in linq (LINQ TO ENTITIES EF6)?

I am calling a stored procedure (PS_StatistiqueEsc) via LINQ, and in the stored procedure i pass 3 parameters start,end and engin (see the code at bottom).
using (var escEnts = new escEntities()) {
var query = escEnts.PS_StatistiqueEsc(Convert.ToDateTime(start),
Convert.ToDateTime(end), engin).ToList();
}
so far so good.
my questions is how can i pass a 4th parameter as a list like (see the code at bottom) or an XML as a parameter:
For Example :
List<int> listToPassInSP = new List<int>();
list.Add(2);
list.Add(3);
list.Add(7);
using (var escEnts = new escEntities()) {
var query = escEnts.PS_StatistiqueEsc(Convert.ToDateTime(start), Convert.ToDateTime(end), engin, listToPassInSP).ToList();
}
Actually the stored procedure accept only 3 parameters ? I am going to changed change my sp which is going to accept a 4th parameter.
The actual SP signature is :
ALTER PROCEDURE [dbo].[PS_StatistiqueEsc]
#dateDebut datetime,
#dateFin datetime,
#EnginName varchar(250)
AS
But will be changed like this :
ALTER PROCEDURE [dbo].[PS_StatistiqueEsc]
#dateDebut datetime,
#dateFin datetime,
#EnginName varchar(250),
#listToPassInSP ???? (i don't know how to declare a variable like a list)
AS
Just want to pass a list to a SP and and the SP must accept a list. How can i do ?

Parameterized stored procedure returning "too many arguments specified"

I'm writing an ASP.NET(C#) application in Visual Studio 2008 and connecting to SQLExpress 2005.
While trying to update a FormView control bound to an SqlDataSource by using a parameterized stored procedure, I constantly get an error screen saying "too many arguments specified".
I have tried clearing the list and adding all the parameters manually before calling the DataSource.Update() method. I have tested with a breakpoint and immediately before the Update method fires, the UpdateParameters collection holds the 8 arguments I have specified in my stored procedure so I know my collection conforms to what I asked for.
Passing in update commands of type="text" that contain an EXEC statement will work but I need it to work by calling the procedure itself.
Has anyone else run into these "extra arguments" or am I playing EPR and chasing imaginary variables?
CREATE PROC spUpdateUserProfile
#UserNameVar nvarchar(256),
#DisplayNameVar varchar(30),
#FNameVar varchar(20),
#LNameVar varchar(20),
#EmailVar varchar(30)=NULL,
#LocationVar varchar(100)=NULL,
#BirthdateVar smalldatetime=NULL,
#BiographyVar varchar(2000)=NULL
AS
UPDATE UserProfile
SET UserDisplayName = #DisplayNameVar,
UserFName = #FNameVar,
UserLName = #LNameVar,
UserSharedEmail = #EmailVar,
UserLocation = #LocationVar,
UserDOB = #BirthdateVar,
UserBiography = #BiographyVar
WHERE UserProfile.UserID =
(SELECT UserProfile.UserID FROM UserProfile
JOIN aspnet_Users ON UserProfile.UserID = aspnet_Users.UserId
WHERE aspnet_Users.UserName = #UserNameVar)
Just a shot in the dark until we can see some code like James asked, but are you settings the DataKeyNames attribute? When I was getting started with FormView and GridView I manually added the primary key value using a hidden field and had the DataKeyNames attribute sent and I think that caused the value to be sent to the stored procedure twice instead of once.
Just a guess
EDIT:
Have you tried
UPDATE UserProfile
SET UserDisplayName = #DisplayNameVar,
UserFName = #FNameVar,
UserLName = #LNameVar,
UserSharedEmail = #EmailVar,
UserLocation = #LocationVar,
UserDOB = #BirthdateVar,
UserBiography = #BiographyVar
WHERE UserProfile.UserID = aspnet_Users.UserId
AND aspnet_Users.UserName = #UserNameVar
change line:
WHERE UserProfile.UserID =
for:
WHERE UserProfile.UserID IN
I've just encountered this as well but I have managed to sort it.
My update was from a grid.
My grid was populated from another stored procedure.
In that Select stored procedure I changed the field names to more user friendly ones
e.g.
select AU.UserName [Member],
Later, when I checked, the Update command was passing all the parameters required by the update stored procedure and extra ones corrsponding to the re-named fields.
I removed the re-naming from the Select procedure and updated the SqlDataSource.
Now only the correct number of fields get passed.
Then I just renamed the HeaderText tag of the GridBoundColumn.e.g.
HeaderText="Member"
I am using a RadGrid rather than the standard GridView but it seems to work there as well.
I checked the number of passed parameters using:
protected void SqlDataSource1_Updating(object sender, SqlDataSourceCommandEventArgs e)
{
for (int x = 0; x <= e.Command.Parameters.Count - 1;x++ )
{
string Type = e.Command.Parameters[x].GetType().ToString();
string Value = e.Command.Parameters[x].ToString();
}
}
Hope this helps

Categories

Resources