Вы пытались заменить
OdbcCommand cmd = new OdbcCommand(@"usp_BS_REPORT_LINE_LIST", _conn);
на
OdbcCommand cmd = new OdbcCommand("{call usp_BS_REPORT_LINE_LIST(?)}", _conn);
If line-count and maintainable code is your only goal, your best bet would be to use any one of the several fine ORM frameworks/libraries available. Class::DBI and DBIx::Class are two fine starting points. Just in case, you are worried about spending additional time to learn these modules - dont: It took me just one afternoon to get started and productive. Using Class::DBI for example your example is just one line:
Table->retrieve(id => $parameter)->column('UPDATE!')->update;
The only down-side (if that) of these frameworks is that very complicated SQL statements required writing custom methods learning which may take you some additional time (not too much) to get around.
Функция «выполнить» принимает массив, содержащий все ваши параметры.
Вам просто нужно найти способ указать, какой дескриптор оператора вы хотите выполнить, и все готово ...
Было бы гораздо лучше хранить ваши дескрипторы операторов где-нибудь, потому что, если вы каждый раз будете создавать новый и готовить его каждый раз, вы действительно не лишаетесь преимуществ "подготовки" ...
Что касается возврата всех строк, вы можете это сделать (что-то вроде "while fetchrow_hashref push") остерегайтесь больших наборов результатов, которые могут съесть всю вашу память!
Нет смысла проверять ошибки после каждого обращения к базе данных. Как утомительно!
Вместо этого, когда вы подключаетесь к базе данных, установите для параметра RaiseError значение true. Затем, если произойдет ошибка базы данных, будет выброшено исключение. Если вы его не поймаете (в блоке eval {}), ваша программа умрет с сообщением, аналогичным тому, что вы делали вручную выше.
Here's a simple approach using closures/anonymous subs stored in a hash by keyword name (compiles, but not tested otherwise), edited to include use of RaiseError
:
# define cached SQL in hash, to access by keyword
#
sub genCachedSQL {
my $dbh = shift;
my $sqls = shift; # hashref for keyword => sql query
my %SQL_CACHE;
while (my($name,$sql) = each %$sqls) {
my $sth = $dbh->prepare($sql);
$SQL_CACHE{$name}->{sth} = $sth;
$SQL_CACHE{$name}->{exec} = sub { # closure for execute(s)
my @parameters = @_;
$SQL_CACHE{$name}->{sth}->execute(@parameters);
return sub { # closure for resultset iterator - check for undef
my $row; eval { $row = $SQL_CACHE{$name}->{sth}->fetchrow_arrayref(); };
return $row;
} # end resultset closure
} # end exec closure
} # end while each %$sqls
return \%SQL_CACHE;
} # end genCachedSQL
my $dbh = DBI->connect('dbi:...', { RaiseError => 1 });
# initialize cached SQL statements
#
my $sqlrun = genCachedSQL($dbh,
{'insert_table1' => qq{ INSERT INTO database.table1 (id, column) VALUES (?,?) },
'update_table1' => qq{ UPDATE database.table1 SET column = 'UPDATE!' WHERE id = ? },
'select_table1' => qq{ SELECT column FROM database.table1 WHERE id = ? }});
# use cached SQL
#
my $colid1 = 1;
$sqlrun->{'insert_table1'}->{exec}->($colid1,"ORIGINAL");
$sqlrun->{'update_table1'}->{exec}->($colid1);
my $result = $sqlrun->{'select_table1'}->{exec}->($colid1);
print join("\t", @$_),"\n" while(&$result());
my $colid2 = 2;
$sqlrun->{'insert_table1'}->{exec}->($colid2,"ORIGINAL");
# ...
Меня очень впечатлил пример Бубакера с использованием закрытия для этого.
Точно так же, если исходной целью было сделать кодовую базу меньше и более удобной в обслуживании, я могу не избавляет от мысли, что из исходного кода требуется убрать много шума, прежде чем кто-либо приступит к преобразованию в CDBI или DBIC и т.д. (несмотря на то, что они обе прекрасные библиотеки.)
Если $ dbh
был создан с RaiseError
, установленным в атрибутах, большая часть этого кода исчезает:
$sql_update = qq { UPDATE database.table
SET column = 'UPDATE!'
WHERE id = ?
};
$sth_update = $dbh->prepare($sql_update);
$sth_update->execute($parameter);
Я не вижу, что обработка ошибок в исходном коде добавляет много такого, чего вы бы не получили из ванильной матрицы
, созданной RaiseError
, но если это важно, взгляните на атрибут HandleError
на странице руководства DBI
.
Кроме того, если такие операторы не используются повторно (что часто является основной целью их подготовки, чтобы кэшировать, как они оптимизированы; другая причина заключается в смягчении последствий SQL-инъекций с помощью заполнителей), то почему бы не использовать do
?
$dbh->do($sql_update, \%attrs, @parameters);