#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