2017-09-13 1 views
0

J'essaie de créer une méthode GetScalar. Nous utilisons beaucoup de DataTables dans les systèmes existants. Je les convertis en EF.Entity Framework - Get Scalar

Voici l'objectif. Il s'agit d'une méthode simple qui prend un nom et des paramètres de procédure stockée, puis renvoie la première ligne, première colonne du jeu de résultats.

public object GetScalar(string command, CommandType type = CommandType.StoredProcedure, List<SqlParameter> parameterList = null) 
    { 
     try 
     { 
      using (var cnn = new SqlConnection(ConnectionString)) 
      { 
       using (var cmd = new SqlCommand(command, cnn)) 
       { 
        cmd.CommandType = type; 

        if (parameterList != null) 
        { 
         foreach (var p in parameterList) 
         { 
          cmd.Parameters.Add(p); 
         } 
        } 

        cmd.Connection.Open(); 
        object obj = cmd.ExecuteScalar(); 
        cmd.Connection.Close(); 
        cmd.Parameters.Clear(); 
        return obj; 
       } 
      } 
     } 
     catch (Exception ex) 
     { 
      Logging.LogError(ex, "MSSqlUtility.GetScalar"); 
      return -1; 
     } 
    } 

Je voudrais avoir une méthode similaire dans EF. Voici ce que j'ai jusqu'ici, mais cela retourne toutes les colonnes - pas seulement la première.

protected T SelectScalar<T>(string inStoredProcedure, ICollection<SqlParameter> inParameters = null) 
    { 
     T result = default(T); 
     if (inParameters != null && inParameters.Count > 0) 
     { 
      string paramNames = string.Join(",", inParameters.Select(parameter => parameter.ParameterName).ToList()); 
      string sqlString = inStoredProcedure + " " + paramNames; 
      object[] paramValues = inParameters.Cast<object>().ToArray();    
      result = Database.SqlQuery<T>(sqlString, paramValues).FirstOrDefault(); 
     } 
     else 
     { 
      result = Database.SqlQuery<T>(inStoredProcedure).FirstOrDefault(); 
     } 

     return result; 
} 

Exemple d'utilisation. Cela renvoie un objet chaîne - "John Doe".

public string GetUserName(string employeeID) 
    { 
     if (string.IsNullOrWhiteSpace(employeeID)) 
     { 
      return string.Empty; 
     } 

     var parameters = new Collection<SqlParameter>();    
     parameters.Add(StoredProcedureParameterBuilder.StringParam("@EmployeeID", employeeID, 20)); 
     return this.SelectScalar<string>("dbo.GetUserName", parameters).Trim(); 
    } 

La requête SQL ressemble à ceci:

SELECT 
    FirstName + ' ' + Last Name 
,EmployeeID 
FROM Users 

Modification de la procédure stockée est pas une option - nous avons besoin de deux colonnes dans d'autres contextes. Le code actuel renvoie à la fois le nom et l'ID. Je voudrais récupérer seulement la première colonne, première rangée, de ce que ma requête peut recracher.

+1

pouvez-vous ajouter un exemple de la façon dont cette méthode est utilisée et à quoi ressemble le résultat? –

Répondre

0

Fini par devoir faire un peu plus de travail manuel. Si quelqu'un a une meilleure solution, je suis tout ouïe, mais cela fonctionne pour mon cas d'utilisation:

/// <summary> 
    /// Selects the first item in the query's result. 
    /// </summary> 
    /// <typeparam name="T"></typeparam> 
    /// <param name="inStoredProcedure">The in stored procedure.</param> 
    /// <param name="inParameters">The in parameters.</param> 
    /// <returns>The first object in the specified type T.</returns> 
    protected T SelectScalar<T>(string inStoredProcedure, ICollection<SqlParameter> inParameters = null) 
    {    
     using (System.Data.IDbCommand command = Database.Connection.CreateCommand()) 
     { 
      try 
      {     
       command.CommandText = inStoredProcedure; 
       command.CommandTimeout = command.Connection.ConnectionTimeout; 

       if(inParameters != null && inParameters.Count > 0) 
       { 
        string paramNames = string.Join(",", inParameters.Select(parameter => parameter.ParameterName).ToList()); 
        command.CommandText += " " + paramNames; 
        foreach (var param in inParameters) 
        { 
         command.Parameters.Add(param); 
        } 
       } 

       Database.Connection.Open(); 
       return (T)command.ExecuteScalar(); 
      } 
      finally 
      { 
       Database.Connection.Close(); 
       command.Parameters.Clear(); 
      } 
     } 
    } 
+2

Je suppose que cela fonctionne, mais il n'utilise pas vraiment Entity Framework du tout. –

+0

Bon point. Après quelques analyses, EF ne fonctionnera pas pour notre usage. Les requêtes provenant d'une seule table sont correctes, mais dès que vous commencez à rejoindre d'autres tables, EF devient assez complexe assez rapidement. –