Вызов нескольких хранимых процедур и представлений сетки одним нажатием кнопки

#c# #asp.net #sql-server-2008 #stored-procedures #gridview

#c# #asp.net #sql-server-2008 #хранимые процедуры #просмотр сетки

Вопрос:

Справочная информация: Я конвертирую время выполнения access, которое выполняет поиск планов по почтовому индексу, типу плана и возрасту.

На данный момент у меня отключен основной поиск с корректным get_zip_plan_age отображением хранимой процедуры, но я не уверен, get_lowest_female_insurance_rate правильно ли я вызываю хранимую процедуру в коде C # и как написать код по-другому для get_lowest_female_rate которого отображается самый низкий процент женщин для каждой возрастной группы по сравнению с get_zip_plan_age которым отображаются все данные.

Вопрос:

  • Как вы вызываете get_lowest_female_rate правильно в исходном коде? Правильно ли то, что у меня есть?
  • Как бы вы написали код хранимой процедуры для get_lowest_female_rate , который отображает самый низкий показатель женского пола для каждой возрастной группы (65, 70, 75, 80)?

Вот скриншот среды выполнения access:

скриншот приложения

Вот мой код для default.aspx.cs:

     protected void Search_Zip_Plan_Age_Button_Click(object sender, EventArgs e)
    {                          
        using (SqlConnection cn = new SqlConnection())
        {
            cn.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings["PriceFinderConnectionString"].ToString();
            cn.Open();

            using (SqlCommand cmd = cn.CreateCommand())
            {
                cmd.CommandText = "get_zip_plan_age";                    
                cmd.CommandType = CommandType.StoredProcedure;

                cmd.CommandText = "get_lowest_female_rate";
                cmd.CommandType = CommandType.StoredProcedure;

                cmd.CommandText = "get_lowest_male_rate";
                cmd.CommandType = CommandType.StoredProcedure;

                cmd.CommandText = "get_carrier_info";
                cmd.CommandType = CommandType.StoredProcedure;


                SqlParameter parm = cmd.CreateParameter(); 
                parm.ParameterName = "@insur_age";
                parm.DbType = DbType.Int64;
                parm.Value = Convert.ToInt64(this.insur_age.Text);
                cmd.Parameters.Add(parm);

                parm = cmd.CreateParameter(); 
                parm.ParameterName = "@zip_code";
                parm.DbType = DbType.String;
                parm.Value = this.ZipCode.Text;
                cmd.Parameters.Add(parm);

                parm = cmd.CreateParameter(); 
                parm.ParameterName = "@plan_code";
                parm.DbType = DbType.String;
                parm.Value = this.PlanCode.Text;
                cmd.Parameters.Add(parm);

                SqlDataReader reader = cmd.ExecuteReader();
                Zip_Plan_Age_GridView.DataSource = reader;
                Zip_Plan_Age_GridView.DataBind();
            }
        }
    }
  

Вот код для хранимой процедуры get_zip_plan_age, которая отображает все данные:

     ALTER PROCEDURE get_zip_plan_age 
-- Add the parameters for the stored procedure here
@zip_code nvarchar(16),
@plan_code nvarchar(16),
@insur_age int = 0 

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

IF @insur_age > 0 
BEGIN 

    SELECT 

      [state_code], 
      [zip_code], 
      [female_value], 
      [male_value], 
      [carrier_name], 
      [update_date], 
      [insur_age], 
      [plan_code], 
      [spousal_discount] 

      FROM [state_zipcode_plans] 

      WHERE (([insur_age] = @insur_age) 
      AND ([zip_code] = @zip_code) 
      AND ([plan_code] = @plan_code)) 

      ORDER BY [male_value], [plan_code]

END  

    ELSE BEGIN

      SELECT 

      [state_code], 
      [zip_code], 
      [female_value], 
      [male_value], 
      [carrier_name], 
      [update_date], 
      [insur_age], 
      [plan_code], 
      [spousal_discount] 

      FROM [state_zipcode_plans] 

      WHERE (([zip_code] = @zip_code) 
      AND ([plan_code] = @plan_code)) 

      ORDER BY [male_value], [plan_code]

END
 END
 GO
  

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

1. Пожалуйста, не ставьте «ASP.NET C # SQL» в названии. Для этого у нас есть теги.

Ответ №1:

В методе Search_Zip_Plan_Age_Button_Click вы установили cmd.Командный текст и cmd.Несколько раз введите команду. В этом случае это должно быть установлено только один раз — они будут иметь значения cmd.Текст команды = «get_carrier_info»; cmd.CommandType = Командный тип.StoredProcedure;

Чтобы сделать ваш код более удобным в обслуживании, подумайте о том, чтобы отделить создание команд от фабрики с помощью шаблона команд.

Что касается sp — я могу видеть sp только для get_zip_plan_age.

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

1. ну ладно. тогда я создам отдельную (SqlCommand cmd123 = cn.createCommand()) для каждой хранимой процедуры, верно?

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

3. Можете ли вы предоставить какой-нибудь пример кода для этого? В настоящее время я несколько раз выписывал инструкцию using(SqlCommand cmd = cn.createCommand()) с разными переменными

Ответ №2:

Моя рекомендация была бы такой: не используйте SqlDataReader , если вы хотите привязать материал к форме, которую пользователь может просматривать / редактировать. Это сохранит соединение с базой данных открытым — потенциально на очень долгое время!

Если вы используете формы для отображения данных, я бы использовал ORM (объектно-реляционное отображение), чтобы вернуть список объектов из вашей базы данных — или, если это не то, что вы хотите, тогда, по крайней мере, используйте DataTable , который получает данные, а затем позволяет вам работать отключенным от базы данных до того момента, когда вам действительно нужно обновить материал (или прочитать новые данные).

Что касается вызова сохраненного процесса:

  • БОЛЬШОЙ бонус за использование using блоков!!
  • Я бы постарался открыть соединение как можно позже — оно не обязательно должно быть открыто во время создания параметров и прочего — открывайте его только перед тем, как вам нужно будет прочитать данные
  • Я бы попытался отделить код пользовательского интерфейса (чтение текстовых полей, привязка к сетке) от фактического кода для загрузки данных — возможно, в какой-то момент вам захочется поместить это на уровень доступа к данным (отдельная библиотека классов) — не смешивайте загрузку данных с повсеместными манипуляциями с пользовательским интерфейсом!
  • Я бы разделил отдельные вызовы на отдельные хранимые процедуры — просто есть четыре метода, которые вы можете вызывать, когда это необходимо, с необходимыми параметрами.

Итак, я бы попытался использовать что-то вроде этого:

 protected void Search_Zip_Plan_Age_Button_Click(object sender, EventArgs e)
{       
    string _connStr = ConfigurationManager.ConnectionStrings["PriceFinderConnectionString"].ConnectionString;

    DataTable data = LoadZipPlanAge(_connStr, .......);

    Zip_Plan_Age_GridView.DataSource = data;
    Zip_Plan_Age_GridView.DataBind();
}


protected DataTable LoadZipPlanAge(string connString, Int64 insurAge, string zipCode, string planCode)
{
    string storedProcName = "dbo.get_zip_plan_age";                    
    DataTable table = new DataTable();

    using (SqlConnection cn = new SqlConnection(connString))
    using (SqlCommand cmd = new SqlCommand(storedProcName, cn))
    {
       cmd.CommandType = CommandType.StoredProcedure;

       // create parameters
       cmd.Parameters.Add("@insur_age", SqlDbType.Int64).Value = int64Value;
       .......


       SqlDataAdapter dap = new SqlDataAdapter(cmd);
       dap.Fill(table);
    }

    return table;
}
  

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

1. спасибо за ваш ответ! Я не собираюсь редактировать какие-либо данные, только отображать их. Так должен ли я использовать ORM или DataTable? Можете ли вы добавить ссылку с дополнительным примером кода для таблиц данных? что еще мне добавить, кроме DataTable data = LoadZipPlanAge(_connStr, …….); ?

2. @Brian McCarthy: если вы хотите отображать только свои данные, то таблица данных была бы просто великолепна. SqlDataAdapter заполнит вашу таблицу данных и создаст необходимые столбцы в этой таблице данных из базового оператора SQL — вам больше ничего не нужно, только код, который я показал. Данные, подлежащие обработке, являются частью ADO.NET — любой ADO.NET в руководстве показано, как работать с таблицами данных и эффективно их использовать.

3. Некоторые ADO.NET ссылки на руководство: ASP Free или C # station

Ответ №3:

Используя логику,

  • Если выбран страховой возраст, отображайте минимальный тариф для женщин только для этого возраста, выбирая верхнее (1) минимальное значение для женщин, ГДЕ возраст соответствует указанному ВОЗРАСТУ
  • Если для страхового возраста выбрано значение ALL, отобразите наименьший показатель для женщин, выбрав верхнее (1) минимальное значение для женщин, ГДЕ почтовый индекс, код плана соответствуют указанным значениям поиска, а коэффициент для мужчин больше 0, Сгруппированные по insur_age, male_value, carrier_name и объединенные для каждого возраста для каждой из возрастных групп 65, 70, 75, 80

Вот хранимая процедура, которую я использовал для получения самого низкого показателя female:

       ALTER PROCEDURE [dbo].[get_lowest_female_rate] 
-- Add the parameters for the stored procedure here
@zip_code nvarchar(16),
@plan_code nvarchar(16),
@insur_age int = 0 

      AS
      BEGIN

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

          -- Insert statements for procedure here

          -- If an Insurance Age is selected, only display the min Female rate for that age 

          IF @insur_age > 0 
          BEGIN 

    SELECT TOP(1)  
      [carrier_name], 
      [insur_age],
      MIN([female_value])

      FROM [state_zipcode_plans] 

      WHERE (([insur_age] = @insur_age) 
      AND ([zip_code] = @zip_code) 
      AND ([plan_code] = @plan_code)
      AND ([female_value] > 0)) 

      GROUP BY        
      [insur_age], [female_value], [carrier_name]

END  

        -- If ALL is selected for Insurance Age, Display Lowest Female Rate for Each of the Age Groups 65, 70, 75, 80 

        ELSE BEGIN

      SELECT TOP(1)           
      [carrier_name], 
      [insur_age],
      MIN([female_value])

      FROM [state_zipcode_plans]

      WHERE  (([zip_code] = @zip_code) 
      AND ([plan_code] = @plan_code)
      AND ([female_value] > 0)
      AND ([insur_age] = 65)) 

      GROUP BY        
      [insur_age], [female_value], [carrier_name]

        UNION 
      SELECT TOP(1)           
      [carrier_name], 
      [insur_age],
      MIN([female_value])

      FROM [state_zipcode_plans]

      WHERE  (([zip_code] = @zip_code) 
      AND ([plan_code] = @plan_code)
      AND ([female_value] > 0)
      AND ([insur_age] = 70)) 

      GROUP BY        
      [insur_age], [female_value], [carrier_name]

UNION 
      SELECT TOP(1)           
      [carrier_name], 
      [insur_age],
      MIN([female_value])

      FROM [state_zipcode_plans]

      WHERE  (([zip_code] = @zip_code) 
      AND ([plan_code] = @plan_code)
      AND ([female_value] > 0)
      AND ([insur_age] = 75)) 

      GROUP BY        
      [insur_age], [female_value], [carrier_name]

       UNION 
      SELECT TOP(1)           
      [carrier_name], 
      [insur_age],
      MIN([female_value])

      FROM [state_zipcode_plans]

      WHERE  (([zip_code] = @zip_code) 
      AND ([plan_code] = @plan_code)
      AND ([female_value] > 0)
      AND ([insur_age] = 80)) 

      GROUP BY        
      [insur_age], [female_value], [carrier_name]     

     END
   END