Единственный метод извлечения данных из SQL Server для различных хранимых процедур, как обрабатывать параметры?

#c# #asp.net #sql-server

Вопрос:

У меня есть один метод в моем вспомогательном классе SQL, а также перегрузка для принятия параметра:

 public static DataTable GetData(string cmd_text)
{
    DataTable dt = new DataTable();

    SqlConnection conn = GetSqlConnection();

    SqlCommand cmd = new SqlCommand
    {
        CommandText = cmd_text,
        CommandType = CommandType.StoredProcedure,
        Connection = conn
    };

    using (SqlDataAdapter da = new SqlDataAdapter(cmd))
    {
        da.Fill(dt);
    }

    return dt;
}
 

Перегрузка:

 public static DataTable GetData(string cmd_text, string p1)
{
    DataTable dt = new DataTable();

    SqlConnection conn = GetSqlConnection();

    SqlCommand cmd = new SqlCommand
    {
        CommandText = cmd_text,
        CommandType = CommandType.StoredProcedure,
        Connection = conn
    };

    //add parameter here somehow?

    using (SqlDataAdapter da = new SqlDataAdapter(cmd))
    {
        da.Fill(dt);
    }

    return dt;
}
 

Однако на полпути мне пришло в голову, что мне нужно передать то же имя параметра, которое ожидает хранимая процедура. Я всегда мог бы обойти это, указав в своем методе другой аргумент для имени параметра или даже настроив параметры в SQL Server так, чтобы они были одинаковыми для всех моих хранимых процедур, но мне было интересно, можно ли это сделать по-другому, либо на C#, либо на SQL.

Моя теория о том, как это можно сделать, заключалась в создании хранимой процедуры-оболочки, которая могла бы вызывать другие хранимые процедуры, но я не совсем уверен, как это можно было бы реализовать, если бы это было возможно.

Комментарии:

1. и у вас всегда есть только один параметр типа string? никогда другие типы данных никогда не имеют более одного параметра?

2. Откуда берутся параметры? Если SP «ищет» параметры, вы должны установить их с cmd.Parameters.Add(...) помощью .

3. @gsharp на данный момент, да. SQL будет неявно преобразовывать практически все, с чем я столкнусь, и все, что я могу перегрузить, но я не ожидаю, что это пройдет мимо всего проекта.

4. Используйте a IDictionary<string,object> p , где ключом является имя параметра, а объектом-значение.

5. @Макс, ты чертов гений, пожалуйста, представь это в качестве ответа.

Ответ №1:

Шаг 0: прекратите использование DataTable

Шаг 1: используйте Dapper

Нет никакого шага 2.

Просто:

 string bar = "ABC"; // just to show usage
var data = connection.Query<YourPoco>(
    "SomeSpName",
    new { foo = 12, bar }, // named args
    commandType: CommandType.StoredProcedure).AsList();
 

Комментарии:

1. @Austin это отлично работает с хранимыми процедурами, как показано в примере, так что: если вы предпочитаете этот маршрут, это все равно нормально

2. Тогда проблема определенно в том, что я ничего не знаю о Щеголе, ха-ха! Мне определенно придется вернуться к этому в будущем, чтобы я мог лучше понять это.

Ответ №2:

Используйте a IDictionary<string,object> p , где ключом является имя параметра, а объектом-значение.

 public static DataTable GetData(string cmd_text, IDictionary<string, object> p1)
{
    DataTable dt = new DataTable();

    SqlConnection conn = GetSqlConnection();
    SqlCommand cmd = new SqlCommand
    {
        CommandText = cmd_text,
        CommandType = CommandType.StoredProcedure,
        Connection = conn
    };

    
    foreach (var p in p1)
    {
        //add parameter here
    }

    using (SqlDataAdapter da = new SqlDataAdapter(cmd))
    {
        da.Fill(dt);
    }

    return dt;
}
 

Ответ №3:

И идеи, что вы могли бы сделать:

  • при запуске программы запросите все sp и все параметры, принадлежащие sp
  • спрячь их где-нибудь
  • перед вызовом sp извлеките параметр из кэша и адаптируйте свою команду SqlCommand

Вот запрос, чтобы получить вашу информацию из базы данных

 SELECT 
   SCHEMA_NAME(SCHEMA_ID) AS [Schema]
  ,SO.name AS [ObjectName]             
  ,SO.Type_Desc AS [ObjectType]
  ,P.parameter_id AS [ParameterID]
  ,P.name AS [ParameterName]
  ,TYPE_NAME(P.user_type_id) AS [ParameterDataType]
  ,P.max_length AS [ParameterMaxBytes]
  ,P.is_output AS [IsOutPutParameter]
FROM sys.objects AS SO
INNER JOIN sys.parameters AS P ON SO.OBJECT_ID = P.OBJECT_ID
ORDER BY [Schema], SO.name, P.parameter_id
 

(Однако я не думаю, что это поможет вам далеко продвинуться, в какой-то момент вам понадобится более одного параметра, другие типы данных и другие причудливые вещи.
Я бы использовал EF или, как предложил Марк Дэппер. Эпоха семьи и друзей закончилась.)

Комментарии:

1. Это кажется замечательной идеей, и, честно говоря, я рассматриваю ее в сравнении с идеей Макса, однако на данный момент идея Макса кажется намного проще в реализации. Я думаю, что буду держать это в заднем кармане, хотя, очень признателен!

2. @Остин, посмотри ответ Марка. Я думаю, что это лучший вариант из всех.