2017-10-18 24 views
1

J'ai la procédure définie par l'utilisateur suivante pour appeler une donnée calculée à partir de la base de données avec 2 paramètres pour renvoyer un entier (*))Exécutez la procédure stockée en utilisant Entity Framework Core 1.1 erreur "erreur": "La clé donnée n'était pas présente dans le dictionnaire"

USE [QIIS2] 
GO 

PROCEDURE [dbo].[sp.GetCansTotals] 
    @startdt datetime2, 
    @enddt datetime2, 
    @hospitalId int 
AS 
BEGIN 
    SET NOCOUNT ON; 

    SELECT COUNT(*) AS TotalCancelled 
    FROM Cans 
    WHERE (OperDt BETWEEN @startdt AND @enddt) 
     AND (hospitalId = @hospitalId); 
END 

le référentiel pour appeler la procédure:

public IEnumerable<Can> getcanstotal(int @hospitalId, string @startdt, string @enddt) 
{ 
    _context.Database.OpenConnection(); 

    DbCommand cmd = _context.Database.GetDbConnection().CreateCommand(); 
    cmd.CommandText = "GetCansTotals"; 
    cmd.CommandType = CommandType.StoredProcedure; 

    IEnumerable<Can> can; 

    using (_context) 
    { 
     can = _context.LoadStoredProc("GetCansTotals") 
          .WithSqlParam("@hospitalId", @hospitalId) 
          .WithSqlParam("@startdt", @startdt) 
          .WithSqlParam("@enddt", @enddt) 
          .ExecuteStoredProc<Can>(); 
    } 

    return can; 
} 

et le contrôleur:

[HttpGet("byParams")] 
public IActionResult GetCanTotals(int hospitalId, string startdt, string enddt) 
{ 
    var cans = _unitOfWork.Cans.getcanstotal(hospitalId, startdt, enddt); 
    return Ok(Mapper.Map<IEnumerable<CanViewModel>>(cans)); 
} 

Voici les EFExctensions.cs pour ExecStoredProced et Maping:

namespace DAL.Extensions 
{ 
    public static class EFExtensions 
    { 
     /// <summary> 
     /// Creates an initial DbCommand object based on a stored procedure name 
     /// </summary> 
     /// <param name="context"></param> 
     /// <param name="storedProcName"></param> 
     /// <returns></returns> 

     public static DbCommand LoadStoredProc(this DbContext context, string storedProcName) 
     { 
      var cmd = context.Database.GetDbConnection().CreateCommand(); 
      cmd.CommandText = storedProcName; 
      cmd.CommandType = System.Data.CommandType.StoredProcedure; 
      return cmd; 
     } 
     /// <summary> 
     /// Creates a DbParameter object and adds it to a DbCommand 
     /// </summary> 
     /// <param name="cmd"></param> 
     /// <param name="paramName"></param> 
     /// <param name="paramValue"></param> 
     /// <returns></returns> 
     public static DbCommand WithSqlParam(this DbCommand cmd, string paramName, object paramValue) 
     { 
      if (string.IsNullOrEmpty(cmd.CommandText) && cmd.CommandType != System.Data.CommandType.StoredProcedure) 
       throw new InvalidOperationException("Call LoadStoredProc before using this method"); 

      var param = cmd.CreateParameter(); 
      param.ParameterName = paramName; 
      param.Value = paramValue; 
      cmd.Parameters.Add(param); 
      return cmd; 
     } 
     /// <summary> 
     /// Executes a DbDataReader and returns a list of mapped column values to the properties of <typeparamref name="T"/> 
     /// </summary> 
     /// <typeparam name="T"></typeparam> 
     /// <param name="command"></param> 
     /// <returns></returns> 
     public static IList<T> ExecuteStoredProc<T>(this DbCommand command) 
     { 
      using (command) 
      { 
       if (command.Connection.State == System.Data.ConnectionState.Closed) 
        command.Connection.Open(); 
       try 
       { 
        using (var reader = command.ExecuteReader()) 
        { 
         return reader.MapToList<T>(); 
        } 
       } 
       finally 
       { 
        command.Connection.Close(); 
       } 
      } 
     } 
     /// <summary> 
     /// Retrieves the column values from the stored procedure and maps them to <typeparamref name="T"/>'s properties 
     /// </summary> 
     /// <typeparam name="T"></typeparam> 
     /// <param name="dr"></param> 
     /// <returns>IList<<typeparamref name="T"/>></returns> 
     private static IList<T> MapToList<T>(this DbDataReader dr) 
     { 
      var objList = new List<T>(); 
      var props = typeof(T).GetRuntimeProperties(); 

      var colMapping = dr.GetColumnSchema() 
       .Where(x => props.Any(y => y.Name.ToLower() == x.ColumnName.ToLower())) 
       .ToDictionary(key => key.ColumnName.ToLower()); 

      if (dr.HasRows) 
      { 
       while (dr.Read()) 
       { 
        T obj = Activator.CreateInstance<T>(); 
        foreach (var prop in props) 
        { 
         var val = dr.GetValue(colMapping[prop.Name.ToLower()].ColumnOrdinal.Value); 
         prop.SetValue(obj, val == DBNull.Value ? null : val); 
        } 
        objList.Add(obj); 
       } 
      } 
      return objList; 
     } 
    } 

} 

Lors du passage de la demande avec postier:

http://localhost:56963/api/cansdatas/byParams?hospitalId=2&startdt=2016-01-01&enddt=2016-12-31 

Erreur:

"error": "The given key was not present in the dictionary."

Quelqu'un pourrait-il aider ??

SOLVED juste de supprimer l'exécution procédure stockée et utilisée le code suivant:

public async Task<IEnumerable<Can>> Get() 
     { 
      return await appContext.Cans.FromSql("GetCansList").ToArrayAsync(); 
     } 
+1

Vous nous montrez une procédure 'GetCanTotals' qui prend trois paramètres - mais la méthode que vous avez appelle' GetCansList' (une autre * procédure * stockée, semble-t-il) qui semble prendre ** aucun paramètre ** - vous ne pouvez donc pas fournir de paramètres à une procédure stockée ne vous attendez pas .... ou êtes-vous simplement en train d'appeler le ** mauvaise ** procédure stockée dans votre code C# ??? –

+0

Vous avez raison, j'ai corrigé le nom de la procédure MAINTENANT j'obtiens l'erreur suivante "error": "Impossible de trouver la procédure stockée 'sp.GetCansTotals'." –

+0

Votre procédure stockée est définie en tant que dbo.sp.GetCansTotals. Pour moi, cela se lit comme base de données = dbo, schéma = sp, procédure stockée = GetCansTotals. Pouvez-vous simplement le définir comme dbo.GetCansTotals et mettre à jour votre référence pour correspondre et voir si cela fonctionne? – natwallbank

Répondre

0

SOLVED juste supprimé la procédure de Exécuter stocké et utilisé le code suivant:

public async Task<IEnumerable<Can>> Get() 
     { 
      return await appContext.Cans.FromSql("GetCansList").ToArrayAsync(); 
     }