Reputation: 117
I have written a table-valued parameter stored procedure, It returns the Id that was inserted. If I run it from a query inside SSMS, it works and returns the value correctly.
When I call the procedure from code, it runs, and inserts the data but does not set the return parameter I have added and marked as a return parameter.
What am I doing wrong here?
SP:
ALTER PROCEDURE [dbo].[InsertUpdateMeeting]
-- Add the parameters for the stored procedure here
@Meeting MeetingsTableType READONLY,
@Area AreasTableType READONLY,
@MeetingLocation MeetingLocationsTableType READONLY
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
DECLARE @MeetingId int = 0;
DECLARE @AreaId int;
DECLARE @MeetingLocationId int;
SELECT TOP 1 @MeetingId=m.MeetingId FROM @Meeting AS m;
SELECT TOP 1 @MeetingLocationId = ml.MeetingLocationId FROM @MeetingLocation AS ml;
SELECT TOP 1 @AreaId = a.AreaId FROM @Area AS a;
UPDATE Areas SET
Hotline=areaParam.Hotline,
Name=areaParam.Name
FROM Areas INNER JOIN @Area AS areaParam
ON Areas.AreaId=areaParam.AreaId;
IF(@@ROWCOUNT=0)
BEGIN;
INSERT INTO Areas
(Hotline,Name)
SELECT areaParam.Hotline,areaParam.Name FROM @Area AS areaParam;
SET @AreaId=SCOPE_IDENTITY();
END;
UPDATE MeetingLocations SET
Address1=ml.Address1,
Address2=ml.Address2,
Address3=ml.Address3,
City=ml.City,
[State]=ml.[State],
Zip=ml.Zip,
ClubName=ml.ClubName,
ClubDescription=ml.ClubDescription,
MapLink=ml.MapLink
FROM MeetingLocations INNER JOIN @MeetingLocation AS ml
ON MeetingLocations.MeetingLocationId=ml.MeetingLocationId;
IF(@@ROWCOUNT=0)
BEGIN;
INSERT INTO MeetingLocations
(Address1,Address2,Address3,City,[State],Zip,ClubName,ClubDescription,MapLink)
SELECT ml.Address1,ml.Address2,ml.Address3,ml.City,ml.[State],ml.Zip,ml.ClubName,ml.ClubDescription,ml.MapLink
FROM @MeetingLocation AS ml;
SET @MeetingLocationId=SCOPE_IDENTITY();
END;
UPDATE Meetings SET
AreaId = @AreaId,
MeetingLocationId=@MeetingLocationId,
Name = meetingParam.Name
FROM Meetings INNER JOIN @Meeting AS meetingParam
ON Meetings.MeetingId=meetingParam.MeetingId;
IF(@@ROWCOUNT=0)
BEGIN;
INSERT INTO Meetings
(MeetingLocationId,AreaId,Name)
SELECT @MeetingLocationId,@AreaId,meetingParam.Name FROM @Meeting AS meetingParam;
SET @MeetingId=SCOPE_IDENTITY();
END;
RETURN @MeetingId;
END
C# code:
...create tables...
var meetingLocationParam = new SqlParameter("@MeetingLocation", meetingLocationTable);
meetingLocationParam.SqlDbType = SqlDbType.Structured;
meetingLocationParam.TypeName = "MeetingLocationsTableType";
var meetingParam = new SqlParameter("@Meeting", meetingTable);
meetingParam.SqlDbType = SqlDbType.Structured;
meetingParam.TypeName = "MeetingsTableType";
var areaParam = new SqlParameter("@Area", areaTable);
areaParam.TypeName = "AreasTableType";
areaParam.SqlDbType = SqlDbType.Structured;
using (var connection = new SqlConnection(conn.ConnectionString))
using (var command = new SqlCommand())
{
connection.Open();
command.Connection = connection;
command.CommandText = "EXEC dbo.InsertUpdateMeeting";
command.Parameters.AddRange(new SqlParameter[]
{meetingParam, areaParam, meetingLocationParam, new SqlParameter()
{
Value=0,
Direction=ParameterDirection.ReturnValue,
SqlDbType=SqlDbType.Int,
ParameterName="@MeetingId"
} });
var otherRet = command.ExecuteNonQuery();
//Assert.IsTrue(ret > 0);
}
Upvotes: 0
Views: 1810
Reputation: 3207
I just noticed you didn't declare your @MeetingId parameter in your SP definition (you did in the body but I don't think that can be used).
ALTER PROCEDURE [dbo].[InsertUpdateMeeting]
-- Add the parameters for the stored procedure here
@Meeting MeetingsTableType READONLY,
@Area AreasTableType READONLY,
@MeetingLocation MeetingLocationsTableType READONLY,
@MeetingId <datatype> OUTPUT -- ADD THIS
AS
Then in your code you can grab it with this:
command.Parameters["@MeetingId"].Value
Upvotes: 0
Reputation: 29212
That output value won't get returned from ExecuteNonQuery
. Try creating a reference to your return parameter like this:
var returnParameter = new SqlParameter[]
{meetingParam, areaParam, meetingLocationParam, new SqlParameter()
{
Value=0,
Direction=ParameterDirection.ReturnValue,
SqlDbType=SqlDbType.Int,
ParameterName="@MeetingId"
} }
command.Parameters.Add(returnParameter);
Then after executing,
var myReturnedValue = returnParameter.Value;
You could also change
RETURN @MeetingId;
to
SELECT @MeetingId;
and then use
var myReturnedValue = (int)command.ExecuteScalar();
Upvotes: 2
Reputation: 5141
There are multiple ways to get a return value from a stored procedure using ADO.NET.
My example are generic methods I've used before. You can pass an SQL command using a stored procedure or text.
SqlAdapter
/// <summary>
/// Returns a DataSet given an Sql Command
/// </summary>
/// <param name="cmd">The SqlCommand object</param>
/// <returns>DataSet</returns>
public static DataSet GetDataSet(SqlCommand cmd)
{
using (SqlConnection con = DbConnect()) // DbConnect() returns SqlConnection instance
{
DataSet ds = new DataSet();
SqlDataAdapter da = new SqlDataAdapter(cmd);
cmd.Connection = con;
da.Fill(ds, "my_dataset");
return ds;
}
}
ExecuteScalar
/// <summary>
/// Returns a single value from the database given an Sql Command object
/// </summary>
/// <param name="cmd">The Sql Command object</param>
/// <returns>string</returns>
public static string GetSingleFromDatabase(SqlCommand cmd)
{
using (SqlConnection con = DbConnect()) // DbConnect() returns SqlConnection instance
{
cmd.Connection = con;
try
{
object returnedValue = cmd.ExecuteScalar();
if (returnedValue != null)
{
return returnedValue.ToString();
}
else
return "";
}
catch (Exception)
{
throw;
}
}
}
Upvotes: 0
Reputation: 9606
You need to either use ExecuteScalar
to catpure the returned value, or use the output
parameter.
A simlar question was answered in this post. Calling stored procedure with return value
Upvotes: 0