Accessing output parameters is a little awkward; you need to add them to the parameters collection in the usual way, with with a .Direction
of Output
. Then you can read the .Value
of the parameter object after executing the method. However: it is much easier to use select
and process it as a result. Note that return
values can be done in a similar way, but with the appropriate .Direction
. The fact that you both output
and return
it, in this case, makes it even more fun... I'd just use the output
part, personally. Or ... throw an exception (raiserrror
).
Something like:
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = "p1";
cmd.CommandType = CommandType.StoredProcedure;
var name = cmd.CreateParameter();
name.ParameterName = "@name1";
name.Value = "abc"; // etc
cmd.Parameters.Add(name);
var err = cmd.CreateParameter();
err.ParameterName = "@rErr";
err.Direction = ParameterDirection.Output;
cmd.Parameters.Add(err);
cmd.ExecuteNonQuery();
if (err.Value is int i)
{
// error i happened
}
}
However: if you'd just used:
raiserror (50001, 16, 1) -- severity needs to be at least 16 here; typically = 16
or (in more recent SQL Server versions):
throw 50001, 'oops', 1
you can get a similar result much more easily; this will result in an Exception
direction from the ADO.NET layer.
(note that you should add the custom error message formally to sysmessages
when using raiserror
- throw
doesn't require that step)
If you used the throw
(or raiserror
) approach, and removed the output
parameter, this entire piece of code could become, with some help from Dapper:
conn.Execute("p1", new { name1 = "abc" }, commandType: CommandType.StoredProcedure);
which is a lot easier to get right!