ADO - ADO.NET Output Parameters and Return Values from Stored Procedures
In ADO.NET, stored procedures can send information back to an application after they are executed. Two common ways of receiving this information are output parameters and return values. Although both allow a stored procedure to communicate a result back to the application, they are used for different purposes. Output parameters are generally used to return one or more pieces of data, while a return value is commonly used to indicate the execution status or result of the stored procedure.
1. Output Parameters
An output parameter is a parameter defined in a stored procedure with the OUTPUT keyword. The stored procedure assigns a value to this parameter, and the ADO.NET application can retrieve that value after the command has been executed.
For example, consider the following SQL Server stored procedure:
CREATE PROCEDURE GetEmployeeCount
@DepartmentId INT,
@EmployeeCount INT OUTPUT
AS
BEGIN
SELECT @EmployeeCount = COUNT(*)
FROM Employees
WHERE DepartmentId = @DepartmentId;
END
Here, @DepartmentId is an input parameter, while @EmployeeCount is an output parameter. The procedure calculates the number of employees belonging to a particular department and places the result in @EmployeeCount.
In ADO.NET, the output parameter can be created using the SqlParameter class:
using System.Data;
using System.Data.SqlClient;
SqlCommand command = new SqlCommand("GetEmployeeCount", connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add("@DepartmentId", SqlDbType.Int).Value = 10;
SqlParameter outputParameter = new SqlParameter(
"@EmployeeCount",
SqlDbType.Int
);
outputParameter.Direction = ParameterDirection.Output;
command.Parameters.Add(outputParameter);
command.ExecuteNonQuery();
int employeeCount = Convert.ToInt32(outputParameter.Value);
The important point is that the value of the output parameter should normally be read after the command has been executed. Before execution, the database has not yet assigned the output value.
2. ParameterDirection.Output
ADO.NET uses the ParameterDirection property to determine how a parameter participates in a database operation.
For an output parameter, the direction is specified as:
outputParameter.Direction = ParameterDirection.Output;
The main parameter directions are:
-
Input— sends a value from the application to the database. -
Output— receives a value from the database. -
InputOutput— sends an initial value to the database and receives an updated value. -
ReturnValue— receives the return value generated by a stored procedure.
The default direction of a parameter is generally Input, so explicitly specifying Output is necessary when creating an output parameter.
3. Returning Multiple Values Using Output Parameters
One advantage of output parameters is that a stored procedure can return several separate values without placing them into a result set.
For example:
CREATE PROCEDURE GetEmployeeDetails
@EmployeeId INT,
@EmployeeName VARCHAR(100) OUTPUT,
@Salary DECIMAL(10,2) OUTPUT
AS
BEGIN
SELECT
@EmployeeName = EmployeeName,
@Salary = Salary
FROM Employees
WHERE EmployeeId = @EmployeeId;
END
The application can create two output parameters:
SqlParameter nameParameter =
new SqlParameter("@EmployeeName", SqlDbType.VarChar, 100);
nameParameter.Direction = ParameterDirection.Output;
SqlParameter salaryParameter =
new SqlParameter("@Salary", SqlDbType.Decimal);
salaryParameter.Direction = ParameterDirection.Output;
command.Parameters.Add(nameParameter);
command.Parameters.Add(salaryParameter);
After execution, both values can be retrieved:
command.ExecuteNonQuery();
string name = Convert.ToString(nameParameter.Value);
decimal salary = Convert.ToDecimal(salaryParameter.Value);
This makes output parameters useful when a procedure needs to return a small number of specific values.
4. Return Values from Stored Procedures
A stored procedure can also use the RETURN statement to send an integer value back to the calling application.
For example:
CREATE PROCEDURE CheckEmployee
@EmployeeId INT
AS
BEGIN
IF EXISTS (
SELECT 1
FROM Employees
WHERE EmployeeId = @EmployeeId
)
RETURN 1;
ELSE
RETURN 0;
END
In this example, the procedure returns 1 when the employee exists and 0 when the employee does not exist.
In ADO.NET, a parameter with ParameterDirection.ReturnValue can be used:
SqlCommand command =
new SqlCommand("CheckEmployee", connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add("@EmployeeId", SqlDbType.Int).Value = 101;
SqlParameter returnParameter =
command.Parameters.Add(
"@ReturnValue",
SqlDbType.Int
);
returnParameter.Direction =
ParameterDirection.ReturnValue;
command.ExecuteNonQuery();
int result =
Convert.ToInt32(returnParameter.Value);
The value stored in result will contain the integer returned by the stored procedure.
5. Output Parameter vs Return Value
Output parameters and return values may appear similar, but their purposes are different.
| Feature | Output Parameter | Return Value |
|---|---|---|
| SQL mechanism | OUTPUT parameter |
RETURN statement |
| Typical data type | Can use various SQL data types | Integer |
| Number per procedure | Multiple output parameters can be used | One return value |
| Common purpose | Return data/results | Indicate status or result code |
| ADO.NET direction | ParameterDirection.Output |
ParameterDirection.ReturnValue |
| Example | Employee name, salary, generated ID | Success/failure or status code |
For example, a procedure could use an output parameter to return a newly created employee ID while using its return value to indicate whether the operation succeeded.
6. InputOutput Parameters
ADO.NET also supports parameters that can both receive an initial value and return a modified value. These parameters use ParameterDirection.InputOutput.
Consider this stored procedure:
CREATE PROCEDURE IncreaseValue
@Value INT OUTPUT
AS
BEGIN
SET @Value = @Value + 10;
END
The application can provide an initial value:
SqlParameter parameter =
new SqlParameter("@Value", SqlDbType.Int);
parameter.Direction =
ParameterDirection.InputOutput;
parameter.Value = 50;
command.Parameters.Add(parameter);
command.ExecuteNonQuery();
int newValue =
Convert.ToInt32(parameter.Value);
The initial value is 50, and the stored procedure changes it to 60. The application can then retrieve the updated value.
7. Important Considerations
When working with output parameters and return values, the application should execute the command before attempting to read the returned values. Developers should also ensure that the parameter name, SQL data type, size, and direction correspond correctly to the stored procedure definition.
Null values require special attention. If the database returns NULL, directly converting the value to a C# type can cause an exception. A safer approach is to check for DBNull.Value:
if (outputParameter.Value != DBNull.Value)
{
int count = Convert.ToInt32(outputParameter.Value);
}
For decimal, string, date, and other data types, the ADO.NET parameter should also be configured with an appropriate database type.
8. Advantages
Output parameters are useful when an application needs a small amount of information from a stored procedure without processing an entire result set. They can reduce unnecessary data transfer and provide a convenient way to return calculated values, generated identifiers, status information, or other specific results.
Return values are especially useful for communicating a simple execution status or numeric result. They can make application logic easier to understand when a stored procedure needs to indicate whether a particular operation was successful.
Conclusion
ADO.NET output parameters and return values provide mechanisms for a stored procedure to communicate information back to the application. Output parameters are suitable for returning one or more specific values, such as an employee ID, count, name, or calculated amount. Return values are generally used for a single integer result, often representing a status or outcome. ADO.NET provides ParameterDirection.Output, ParameterDirection.InputOutput, and ParameterDirection.ReturnValue to handle these different scenarios. Understanding the distinction between these mechanisms helps developers design cleaner and more efficient database applications.