18

Using EF, I'm trying to execute a stored procedure that returns a single string value, i.e. the status of an SQL Agent Job.

The stored procedure is declared as

CREATE PROCEDURE [dbo].[up_GetJobStatus](@JobStatus NVARCHAR(30) OUTPUT)
AS

-- some code omitted for brevity

SELECT @JobStatus = (
SELECT  
    CASE job_state 
    WHEN 1 THEN 'Executing'
    WHEN 2 THEN 'Waiting for thread'
    WHEN 3 THEN 'Between retries'
    WHEN 4 THEN 'Idle'
    WHEN 5 THEN 'Suspended'
    WHEN 6 THEN '<unknown>'
    WHEN 7 THEN 'Performing completion actions'
END
FROM @xp_results results 
INNER JOIN msdb.dbo.sysjobs sj
ON results.job_id = sj.job_id
WHERE sj.job_id = @job_id)

RETURN

I have verified the stored procedure is working correct as I can execute it in query window and it returns

    @JobStatus
  ------------
  1|Idle

However when executing with EF, the param value is NULL

var param = new SqlParameter
{
    ParameterName = "@JobStatus",
    DbType = DbType.String,
    Size = 30,
    Direction = System.Data.ParameterDirection.Output
};

var result = this.etlContext.Database.SqlQuery<string>("EXEC dbo.up_GetJobStatus @JobStatus OUTPUT", param);

I've also tried the ExecuteSqlCommand method but that didn't work either.

Any ideas?

empo
  • 1,133
  • 5
  • 21
  • 41

5 Answers5

37
  1. Create stored procedure in database

    CREATE PROCEDURE [dbo].myStoredProcName
        @inputParam1 VARCHAR(150),
        @inputParam2 VARCHAR(150),
        @myOutputParamBool BIT OUTPUT,
        @myOutputParamString VARCHAR(100) OUTPUT,
        @myOutputParamInt INT OUTPUT
    AS
    BEGIN
        -- sql here
    END
    
  2. Update entity model from database to include stored procedure as shown here

  1. Call the stored procedure from C# code

    // Type is System.Data.Entity.Core.Objects.ObjectParameter
    ObjectParameter myOutputParamBool = new ObjectParameter("myOutputParamBool", typeof(bool));
    ObjectParameter myOutputParamString = new ObjectParameter("myOutputParamString", typeof(string));
    ObjectParameter myOutputParamInt = new ObjectParameter("myOutputParamInt", typeof(Int32));
    
    using (var context = new SandCryptEntities())
    {
        context.myStoredProcName(inputParam1, inputParam2, myOutputParamBool, myOutputParamString, myOutputParamInt);   
    }
    
    bool myBool = Convert.ToBoolean(myOutputParamBool.Value);
    string myString = Convert.ToString(myOutputParamString.Value);
    int myInt = Convert.ToInt32(myOutputParamInt.Value);
    
Michael Myers
  • 188,989
  • 46
  • 291
  • 292
Augis
  • 1,903
  • 1
  • 16
  • 21
4

Here's an actual answer. Apparently there are serious issues with output parameters in entity framework when you're using DbContext/code first. This article has a good discussion and workaround: http://weblogs.asp.net/dwahlin/using-entity-framework-code-first-with-stored-procedures-that-have-output-parameters. Apparently it's supposed to be "fixed" with an update, but I haven't really seen that happen.

sovemp
  • 1,402
  • 1
  • 13
  • 31
3

Use the following code. It is working for me.

var param = new SqlParameter
{
    ParameterName = "@JobStatus",
    DbType = DbType.String,
    Size = 30,
    Direction = System.Data.ParameterDirection.Output
};

var result = this.etlContext.Database.SqlQuery<string>("EXEC dbo.up_GetJobStatus @JobStatus=@JobStatus OUTPUT", param);
string JobStatus = param.Value.ToString();

The first @JobStatus is your param ParameterName and the second @JobStatus is the PROCEDURE Parameter name.

Michael Myers
  • 188,989
  • 46
  • 291
  • 292
vicky
  • 1,546
  • 1
  • 18
  • 35
2

Just to build on vicky's answer.

var localPar = new SqlParameter("@userlogin", ad);
var Paramater2 = new SqlParameter("@Paramater2", "");
Paramater2.Direction = ParameterDirection.Output;
Paramater2.Size = 30;
Paramater2.DbType = DbType.String;

var parameters = new List<SqlParameter>();
parameters.Add(localPar);
parameters.Add(Paramater2);


var result = this.Database.SqlQuery<object>("EXEC dbo.uspSP @userlogin, @Paramater2 =@Paramater2 OUTPUT", parameters.ToArray());

var x = result.FirstOrDefault();

return Paramater2.Value.ToString();

If you have more than 1 parameter.

Michael Myers
  • 188,989
  • 46
  • 291
  • 292
Richard Housham
  • 1,525
  • 2
  • 15
  • 31
0

Just need a slight change.

First Building Your Query-

var query=@"$Declare @return_Value nvarchar(30) @JobStatus nvarchar(30)
EXEC @return_Value=up_GetJobStatus @JobStatus=@JobStatus
SELECT @JobStatus as N'@JobStatus'";

Secondly, using SqlQueryRaw.

var result = this.etlContext.Database.SqlQueryRaw<string> 
("query").AsEnumerable().FirstOrDefault();

result should have the value you are looking for.