2013-01-09 17 views
11

Próbuję wywołać procedurę przechowywaną using Dapper.Net i uzyskać wartości zwracane.Wartości zwracane przez zapytanie Dapper.net z procedurą składowaną

p.Add("@INCIDENT_ID", dbType: DbType.Int32, direction: ParameterDirection.ReturnValue); 

var retResults = con.Execute("usp_GetIncidentID", p, commandType:CommandType.StoredProcedure); 

int IncidentID = p.Get<int>("INCIDENT_ID"); 

Próbowałem kilka różnych rzeczy z kierunku parametru i używając "@INCIDENT_ID". Jeśli przejdziesz przez wyniki, zobaczysz, że odpowiednie wartości zwracane są obniżane w wartości retResults, ale nie mam dostępu do wartości w sposób opisany poniżej w dokumentacji.

Procedury przechowywane Wytworny obsługuje w pełni przechowywane procs:

var user = cnn.Query<User>("spGetUser", new {Id = 1}, 
    commandType: CommandType.StoredProcedure).First();}}} 
If you want something more fancy, you can do: 

var p = new DynamicParameters(); 
p.Add("@a", 11); 
p.Add("@b", dbType: DbType.Int32, direction: ParameterDirection.Output); 
p.Add("@c", dbType: DbType.Int32, direction: ParameterDirection.ReturnValue); 

cnn.Execute("spMagicProc", p, commandType: commandType.StoredProcedure); 

int b = p.Get<int>("@b"); 
int c = p.Get<int>("@c"); 
+0

Co masz na myśli: "Nie jestem w stanie uzyskać dostępu do wartości w sposób opisany w dokumentacji" – MethodMan

+1

Czy wypróbowany 'var IncidentID = con.Query (" usp_GetIncidentID ", commandType: CommandType.StoredProcedure) .SingleOrDefault();'? To jest najprostsze i będzie działać, jeśli procedura składowana zwraca wartości przez "wybierz" –

+0

Po prostu wypróbowałem, wracam {DapperRow, INCIDENT_ID = '902306'}}, które udało mi się zobaczyć wcześniej, ale mając problemy z uzyskaniem dostępu do tej wartości. – yellowfever

Odpowiedz

0

można odczytać wartość jak poniżej

var incidentId = retResults.ToList()[0].INCIDENT_ID; 
+2

Nie działa, gdy próbujesz uzyskać wartość zwracaną z pustym zestawem wyników! – alerya

5

I podejrzany (niesprawdzone), że jest to czysto niedopasowanie w jaki sposób nazwa parametru; spróbuj (nota wyjętą @):

p.Add("INCIDENT_ID", dbType: DbType.Int32, direction: ParameterDirection.ReturnValue); 

var retResults = con.Execute("usp_GetIncidentID", p, commandType:CommandType.StoredProcedure); 

int IncidentID = p.Get<int>("INCIDENT_ID"); 
+0

Marc, bawiłem się symbolem "@", czytałem gdzieś, co robiło różnicę, ale tak się nie stało. Odzyskuję prawidłowe wartości, ponieważ mogę spojrzeć na okno zegarka i zobaczyć wartości w wyniku. Nie jestem do końca pewien, jak uzyskać "właściwą" drogę. dawny. retResults = {DapperRow, INCIDENT_ID = '902479'} Dzięki za odpowiedź! – yellowfever

+0

Czy wynik zawiera siatkę danych? Pytanie sugerowało, że aktualizujesz parametry ... –

+0

Marc, tak, to jest wynik. Jak rozumiem dokumentacji, masz przekazać wartości jako parametr z typem zwracanym "ParameterDirection.ReturnValue". Wyniki wracają poprawnie, nie jestem w stanie mapować do tych wyników za pomocą "p.get (" INCIDENT_ID "). To jest ta część, której nie dostaję, dlaczego nie mogę uzyskać właściwej wartości od the dynamicParameter. I jeszcze raz dziękuję za odpowiedź, Jest to bardzo cenne. – yellowfever

0

wpadłem na podobny problem z odczytem wyniki QueryMultiple. Pierwsze wywołanie Read() zwróciło poprawny typ, a drugie zwróciło DapperRow. Zauważyłem, że za pomocą wpisanej wersji Read():

rozwiązałem mój problem.

+1

co jeśli zestaw wyników ma 0 wierszy i masz zwracaną wartość? – alerya

0

Przepisałem to dla uproszczenia. Używam parametrów wyjściowych, ponieważ daje mi to pełną kontrolę nad przekazywanym typem danych. Mogę zastosować to podejście w każdym innym scenariuszu, a nie tylko w wstawkach.

Przechowywane Proc:

ALTER PROCEDURE User_Insert (
@EmailAddress nvarchar(255), 
@Id bigint OUT 
) AS 
INSERT INTO User (
     [EmailAddress] 
    ) VALUES (
     @EmailAddress 
    ) 
    set @Id = SCOPE_IDENTITY() 

Respository Kod:

var sql = "Execute User_Insert @EmailAddress, @Id = @Id OUTPUT"; 
var _params = new DynamicParameters(); 
_params.Add("EmailAddress", user.EmailAddress); 
_params.Add("Id", dbType: DbType.Int64, direction: ParameterDirection.Output); 

using (var connection = new SqlConnection(ConnectionString)) { 
    connection.Open(); 
    using (var transaction = connection.BeginTransaction()) { 
     var result = SqlMapper.Execute(connection, sql, param, transaction); 
     transaction.Commit(); 
    } 
}  
var id = _params.Get<long>("Id"); 
0

Korzystanie z wersji testowej Dapper, znalazłem ten działa jak czar:

result = dbConnection.ExecuteScalar<int>(typeof(UCCCCException).Name + "_c", 
         obj, commandType: CommandType.StoredProcedure); 

piszę ogólny do użycia przy wstawianiu obiektów dowolnego typu do bazy danych.

Procedura przechowywana wygląda następująco:

ALTER PROCEDURE [dbo].[UCCCCException_c] 
(
@Id int = null, 
@ExceptionDate datetime = null, 
@HResult int = 0, 
@Message varchar(8000) = null, 
@Source varchar(8000) = null, 
@StackTrace varchar(8000) = null, 
@Module varchar(8000) = null, 
@Name varchar(8000) = null, 
@created_at datetime = null, 
@updated_at datetime = null, 
@created_by int = null, 
@updated_by int = null 
, 
@Creator varchar(255) = null, 
@Updator varchar(255) = null 
) 
AS 

-- SET NOCOUNT ON added to prevent extra result sets from 
-- interfering with SELECT statements. 
SET NOCOUNT ON; 

Insert into dbo.uccccexceptions (ExceptionDate, HResult, [Message], [Source], StackTrace, Module, Name) 
          values (
            coalesce(@ExceptionDate,getdate()), 
            @HResult, 
            @Message, 
            @Source, 
            @StackTrace, 
            @Module, 
            @Name 
            ) 
            ; 
select @@Identity; 
go 

Te zastrzeżenia w tej sprawie jest to, że należy określić pozycję dla każdej nieruchomości w klasie używasz, nawet jeśli te właściwości nie istnieje w tabeli docelowej , jako parametr procedury składowanej. Może to być denerwujące, jeśli masz wiele pól, które są polami widoku w sytuacjach MVC.

Aby uzyskać wartość zwracaną, wystarczy użyć polecenia Wykonaj i upewnić się, że ostatnia instrukcja to Wybierz @@ Tożsamość w procedurze przechowywanej.

To działa doskonale i pozwala mi napisać polecenie rodzajowe insert w moim repozytorium jak poniżej:

 public virtual int Insert(T obj) 
    { 
     int result = -2; 
     if (!databaseOnline) 
     { 
      throw new Exception(HttpStatusCode.ServiceUnavailable.ToString()); 
     } 
     if (obj != null) 
     { 
      try 
      { 
       using (IDbConnection dbConnection = ConnectionProvider.OpenConnection()) 
       { 
        dbConnection.Open(); 
        result = dbConnection.ExecuteScalar<int>(typeof(T).Name + "_c", 
         obj, commandType: CommandType.StoredProcedure); 
       } 
      } 
      catch (SqlException sqlex) 
      { 
       Logger.LogError(sqlex, false); 
       throw; 
      } 
      catch (Exception ex) 
      { 
       Logger.LogError(ex); 
       throw; 
      } 
     } 
     return result; 
    } 

używam konwencję w mojej bazy danych, że nazwa procedura przechowywana jest nazwa typu następnie "_s" dla wybierz, "_ c" dla wstawienia, "_d" dla usunięcia i "_u" dla aktualizacji.

PS: Nienawidzę używać DynamicParameters Dappera ani żadnego innego urządzenia, które wymaga użycia innej metody wstawiania lub aktualizacji dla każdej klasy w ogólnym repozytorium.

0

Rozwiązanie DynamicParameters nie jest dla mnie czyste. Znacznie lepiej jest, aby kod procedury przechowywanej zwrócił liczbę całkowitą (Wybierz 1;) i używaj eleganckiego ExecuteScalar<int>("[sp_name]", params);

Powiązane problemy