Alternative way to get output parameter from store

2019-01-25 17:07发布

问题:

I love using Dapper for my ORM needs but I know there must be a better way to insert/update my sql server database using a stored procedure and strongly typed Lists.

For example:

I have a class Song:

    public class Song
{
    public int Id { get; set; }
    public string title { get; set; }
    public string genre { get; set; }
}

and somebody submits a List of songs:

 List<Song> songs = new List<Song> { 
            new Song { Id = 1, title = "Song 1" , genre="rock"}, 
            new Song { Id = 2, title = "Song 2" , genre="disco"}};

I want to update the database using my stored procedure which either inserts the new song or updates it if the song already exists. My stored procedure has two output parameters: @success_added int = 0 and @success_updated int = 0

my sproc is as follows:

ALTER PROCEDURE [dbo].[UpdateSong] 
@Id int = 0, 
@title varchar(25) = NULL,
@genre varchar(25) = NULL,
@success_updated bit = 0 OUTPUT,
@success_added bit = 0 OUTPUT
AS
IF NOT EXISTS (SELECT Id  FROM Songs WHERE Id = @Id)
    BEGIN
        INSERT INTO Songs
        (
        -- Id created by db
        title,
        genre
        ) 
        VALUES
        (
        @title, 
        @genre
        )
        SELECT @Success_Added = 1, @Success_Updated = 0
    END
ELSE -- song already exists
    BEGIN
        UPDATE Songs  
        SET
        title = @title,
        @genre = @genre
        WHERE Id = @Id
        SELECT @Success_Added = 0, @Success_Updated = 1
    END
RETURN

I know this works:

dbConn.Open();
DynamicParameters p = new DynamicParameters();
foreach (var song in songs)
  {
    p.Add("@Id", song.Id);
    p.Add("@title", song.title);
    p.Add("@genre", song.genre);
    p.Add("@success_updated", dbType: DbType.Boolean, direction: ParameterDirection.Output);
    p.Add("@success_added", dbType: DbType.Boolean, direction: ParameterDirection.Output);
    dbConn.Execute("Test_UpdateSong", p, commandType: CommandType.StoredProcedure);
    Console.WriteLine("@success_added: " + p.Get<Boolean>("@success_added"));
    Console.WriteLine("@success_updated: " + p.Get<Boolean>("@success_updated"));
  }
dbConn.Close();

But that requires manually converting each Song property to a anonymous type DynamicParameter. I'd rather simply do this:

dbConn.Open();
foreach (var song in songs)
  {
    var updateResult = dbConn.Query<dynamic>("Test_UpdateSong", song, commandType: CommandType.StoredProcedure);
  }
dbConn.Close();

Which also works. But, now how do I get my output parameters?

回答1:

As I stated originally, I didn't want to have to manually convert each class property to a Dapper dynamic parameter. This is critical because if I create a generic method, I may not know which class is being passed into the method and thus which properties to pass to convert to dynamic parameters. Taking @Metro Smurfs advice (when all else fails read the directions), I looked into the Dapper test class and found a solution that works for me:

DynamicParameters p = new DynamicParameters(song);

by adding the song object to the DynamicParameters constructor, a DynamicParameters template is created which will automatically convert all properties to parameters. Then I can simply add my two output parameters and execute the sproc:

p.Add("@success_updated", dbType: DbType.Boolean, direction: ParameterDirection.Output);
p.Add("@success_added", dbType: DbType.Boolean, direction: ParameterDirection.Output);
dbConn.Execute("Test_UpdateSong", p, commandType: CommandType.StoredProcedure);
// get my output parameters...
var success_added = p.Get<bool>("@success_Added");
var success_added = p.Get<bool>("@success_Updated");

and I'm good to go! Thanks to @Nick and @Metro Smurf for the suggestions!



标签: dapper