2016-07-04 6 views
-1

Ich versuche, ExecuteNonQuery in C# zu implementieren. Die gespeicherte Prozedur selbst funktioniert einwandfrei, wenn ich in SQL ausführe. Es gibt eine GUID für SubmissionId und den Text 'submit sequence' für SubmitSequence zurück. Aber in .net, es ist ein Zeichen der Rückkehr als Ausgang für SubmitSequencegekürzter Ausgabeparameter von exuctenonquery

ALTER PROC [dbo].[test_SP] 
(
    @FormId uniqueidentifier, 
    @FormCode varchar(10), 
    @FormTitle nvarchar(200), 
    @User nvarchar(50), 
    @Url nvarchar(255) = NULL, 
    @Host nvarchar(50), 
    @RemoteHost nvarchar(50) = NULL, 
    @UserAgent nvarchar(255) = NULL, 
    @Referrer nvarchar(255) = NULL, 
    @SubmissionId uniqueidentifier out, 
    @SubmitSequence varchar(30) out 
) AS 

BEGIN 

SET @SubmissionId = newid(); 
set @SubmitSequence = 'submit sequence' 

-- INSERT Query 
SELECT 
    @SubmissionId as SubmissionId, @SubmitSequence as SubmitSequence 
END 

Aber in der .net, erhalte ich die GUID für SubmissionId (was richtig ist) und der Text ‚s‘ für SubmitSequence.

public SubmissionHeaderDTO GetRefNo() 
     { 
      var inPrms = new Dictionary<string, object>(StringComparer.InvariantCultureIgnoreCase) 
          { 
           {"FormId", Guid.NewGuid()}, 
           {"FormCode", "TST"}, 
           {"FormTitle", "Test form"}, 
           {"User", "test"}, 
           {"Host", "iisserver"}        
          }; 
      var outPrms = new Dictionary<string, object>(StringComparer.InvariantCultureIgnoreCase) { 
          { "SubmissionId", Guid.NewGuid() }, 
          { "SubmitSequence", "two"} 
          }; 
      var result = DBHelper.ExecSP(Constants.SPNames.SubmissionHeaderInsert, inPrms, outPrms); 
      SubmissionHeaderDTO refNo = DictionaryToObject<SubmissionHeaderDTO>(result); 
      return refNo; 
     } 

DBHelper.cs

public static Dictionary<string, object> ExecSP(string sp, Dictionary<string, object> paramIn, Dictionary<string, object> paramOut) 
     { 
      var dbAccess = new DBAccess(); 
      var results = dbAccess.ExecuteQuery(sp, paramIn, paramOut); 
      return results; 
     } 

DBAccess.cs

public class DBAccess 
    { 
     public Dictionary<string, object> ExecuteQuery(string storedProcedure, Dictionary<string, object> parameters, 
              Dictionary<string, object> outParameters) 
     { 

      using (var sqlConn = new SqlConnection(Configuration.DBConnection)) 
      { 
       sqlConn.Open(); 
       using(var transaction = sqlConn.BeginTransaction("Results")) 
       { 
        using(var sqlcmd = new SqlCommand(storedProcedure, sqlConn, transaction)) 
        { 
         sqlcmd.CommandType = CommandType.StoredProcedure; 
         foreach(var kv in parameters) 
         { 
          sqlcmd.Parameters.AddWithValue(kv.Key, kv.Value); 
         } 
         foreach(var kv in outParameters) 
         { 
          sqlcmd.Parameters.AddWithValue(kv.Key, kv.Value).Direction = ParameterDirection.Output; 
         } 

         try 
         { 
          sqlcmd.ExecuteNonQuery(); 
          var result = GetOutputParameters(sqlcmd.Parameters); 
          transaction.Commit(); 
          return result; 
         } 
         catch(Exception) 
         { 
          transaction.Rollback(); 
          throw; 
         } 
        } 
       } 
      } 

     } 

     private Dictionary<string, object> GetOutputParameters(SqlParameterCollection paramCollection) 
     { 
      var returnParameters = new Dictionary<string, object>(); 
      foreach (SqlParameter par in paramCollection) 
      { 
       if ((par.Direction == ParameterDirection.Output) || (par.Direction == ParameterDirection.ReturnValue)) 
       { 
        returnParameters.Add(par.ParameterName, par.Value); 
       } 
      } 
      return returnParameters; 
     } 
    } 
+0

Output params nicht Teil des Verfahrens der Ergebnismenge sein sollen - Sie sollten nicht 'SELECT'ing Sie. Behalten Sie die SET-Anweisungen bei, entfernen Sie aber die SELECT-Anweisung und sehen Sie, ob dies einen Unterschied macht. – Crowcoder

+0

Nein, es machte keinen Unterschied. Ich habe gerade die SET-Anweisungen verlassen. Der Ausgabeparameterwert für die Übermittlungssequenz ist nur das erste Zeichen. – Rama

Antwort

1

habe ich Ihren Code in meine eigene Lösung und das Problem neu erstellt. Sie geraten in einen der Gründe, warum Sie eigentlich nie tun sollten AddWithValue. Da Sie eine generische object hinzufügen, gibt es keine Möglichkeit, abzuleiten, welcher Datentyp der SQL-Parameter sein sollte. Wenn Sie vor ExecuteNonQuery brechen und die Parameterliste überprüfen, sehen Sie, dass es als NVARCHAR ohne Länge definiert ist. Also standardmäßig ist es Länge 1. Sie müssen Ihre SQL-Parameter mit einem echten SqlDbType bauen, und Sie sollten sie mit der Value Eigenschaft anstelle von AddWithValue setzen.

UPDATE

Zum dynamischen Abfrage der Parameter Meta-Daten Blick auf diese ersten Schritte. Beachten Sie noch mehr Arbeit zu tun, wie die Abbildung der SQL-Typen zu SqlDbType:

DECLARE @spName sysname; 
SET @spName = 'test_SP'; 

DECLARE @objId int; 
SELECT @objId = ISNULL([object_id], 0) FROM sys.procedures WHERE [name] = @spName; 

SELECT p.[name], p.[system_type_id], t.[name], p.[max_length], p.[precision], 
    p.[scale], p.[is_output], p.[is_nullable] 
FROM sys.parameters p 
INNER JOIN sys.systypes t 
    ON p.[system_type_id] = t.[xtype] 
WHERE [object_id] = @objId; 

enter image description here

+0

Ich muss ein generisches Objekt in meinem Fall verwenden. Könnten Sie bitte vorschlagen, wie kann ich 'Add' mit SqlDbType und Länge in meinem Fall ohne AddWithValue verwenden – Rama

+0

Sie können die 'sys.parameters' Sicht abfragen, um herauszufinden, die Parameter Metadaten für eine gespeicherte Prozedur zur Laufzeit. – Crowcoder

+0

Es gibt alle Ausgabeparameter mit Ausnahme von NVarchar zurück. Könnte irgendjemand bitte eine linq schreiben, um die Parameter sqldbtype = nvarchar und parameterdirection = output zu extrahieren und die Größe dieses Parameters auf 100 zu setzen. Das wird meinen Zweck lösen – Rama

Verwandte Themen