Я уже реализовал хранимую процедуру CLR, которую я опишу ниже, и она работает достаточно хорошо.Но я не уверен, что мне действительно нужен CLR для этого, или решение среднего уровня было бы столь же производительным и обслуживаемым.
В существующей кодовой базе эта компания накопила 500+ поисковых запросовпроцедуры на протяжении многих лет.Теперь они хотят, чтобы я написал механизм агрегации, который работает для всех этих хранимых процедур.Каждая хранимая процедура поиска в их системе имеет сходный формат, поэтому я знаю, как программно вызывать их с правильными параметрами и т. Д.
Я не хочу каким-либо образом изменять каждую хранимую процедуру поиска.Я предпочел бы сначала вставить результаты хранимой процедуры во временную таблицу.Затем я могу запустить механизм агрегирования, запросив временную таблицу.
Проблема в том, что в SQL Server нельзя вставить результаты хранимой процедуры, если вы не знаете схему EXACT результатов хранимой процедуры.Но это на самом деле невозможно, потому что хранимые процедуры могут возвращать разные схемы результатов в зависимости от параметров.
Поэтому, чтобы гарантировать, что хранимая процедура вернет ожидаемую схему EXACT, я создал «SP_Wrapper»"Хранимая процедура CLR.В этой оболочке я вызываю хранимую процедуру и «адаптирую» каждую запись к моей ожидаемой схеме.Затем я возвращаю адаптированный набор результатов.
Затем я могу вставить в свою временную таблицу, зная, что схема была правильной.
Теперь, допустим, я адаптировал результаты на среднем уровне.Я должен был бы сначала вернуть результат на средний уровень.Итерируйте их, адаптируйте каждую запись, затем вставляйте отдельно или массовую копию.
Это казалось правильным выбором, но теперь мне нужно развернуть эту хранимую процедуру CLR.Я действительно много здесь получаю?
using (var conn = new SqlConnection("context connection=true"))
{
conn.Open();
//load result table schema
resultColumns = SqlSchema.getTempTableMeta(conn, resultTableName);
//load parameter table schema - may not exist
var hasParams = !String.IsNullOrEmpty(paramTableName);
parameters = SqlSchema.getTempTableMeta(conn, paramTableName);
SqlCommand command;
SqlDataReader reader = null;
///Load Parameter Values
if (hasParams)
{
command = conn.CreateCommand();
command.CommandText = $@"if( object_id('tempdb..{paramTableName}') is not null) select top 1 * from {paramTableName};";
command.CommandType = CommandType.Text;
reader = command.ExecuteReader();
using (reader)
{
while (reader.Read())
{
foreach (var p in parameters)
{
var val = reader[p.Name];
if (!String.IsNullOrWhiteSpace(val?.ToString()))
parameter_values[p.Name] = val;
}
}
}
}
SqlDataRecord record = new SqlDataRecord(resultColumns.ToArray());
//////mark the beginning of the result set
SqlContext.Pipe.SendResultsStart(record);
command = conn.CreateCommand();
command.CommandType = CommandType.StoredProcedure;
command.CommandText = spName;
foreach (var p in parameters)
{
if (parameter_values.ContainsKey(p.Name))
command.Parameters.Add(
new SqlParameter
{
ParameterName = p.Name,
SqlDbType = p.SqlDbType,
Value = parameter_values[p.Name]
}
);
}
var cmdReader = command.ExecuteReader();
using (cmdReader)
{
while (cmdReader.Read())
{
int sequence = 0;
foreach (var resultColumn in resultColumns)
{
var resultColumnValue = cmdReader[resultColumn.Name];
var t = resultColumn.SqlDbType;
resultColumnValue = SqlSchema.Convert(resultColumnValue, SqlSchema.sqlTypeMap[t]);
record.SetValue(sequence, resultColumnValue);
sequence++;
}
SqlContext.Pipe.SendResultsRow(record);
}
}
// Mark the end of the result-set.
SqlContext.Pipe.SendResultsEnd();
conn.Close();
}