#c# #sql-server #ado.net
#c# #sql-server #ado.net
Вопрос:
У меня есть этот скрипт SQL-запроса, который я пытаюсь вызвать через ADO.Net код.
DECLARE
@Error NVARCHAR(MAX)
DECLARE
@Errors TABLE
(
[Column_Name] VARCHAR(MAX),
[Message] VARCHAR(MAX)
)
IF NOT EXISTS(...)
BEGIN
INSERT INTO @Errors
SELECT
'Col1',
'value does not exist.'
END
IF NOT EXISTS(...)
BEGIN
INSERT INTO @Errors
SELECT
'Col2',
'value does not exist.'
END
IF EXISTS (SELECT * FROM @Errors)
BEGIN
SET @Error = (
SELECT
[Column_Name],
[Message]
FROM
@Errors
FOR JSON PATH, INCLUDE_NULL_VALUES
);
SELECT @Error AS 'Error_Message'
END
ELSE
BEGIN
SELECT TOP(1) Id
FROM dbo.table
END
Это код C #
using (var conn = await _connectionFactory.OpenConnectionAsync(database: "dbName", readOnly: true))
{
using (var cmd = conn.CreateCommandFromSqlFile(path, "test.sql"))
{
string errors = string.Empty;
Guid id;
using (DataReader reader = await cmd.ExecuteReaderAsync(ct))
{
if (reader.HasRows)
{
while (await reader.ReadAsync(ct))
{
errors = reader.GetString("Error_Message");
id = reader.GetGuid("Id");
}
}
}
}
}
Сценарий SQL всегда возвращает либо, Error_Message
либо Id
в зависимости от условия. Если @Errors
таблица заполнена, она возвращает Error_Message
, и если ошибок нет, то она возвращает Id
.
Я пытаюсь получить эти значения в коде c #, но он выдает исключение в while
блоке, поскольку одно из значений, либо Error_Message
либо Id
, не будет присутствовать.
Мне нужна помощь в том, чтобы корректно добавить эти значения в мой код C #. Есть ли способ сделать это?
Комментарии:
1. Используйте выходные параметры.
2. @DaleK — Сценарий SQL не является хранимой процедурой или функцией, это просто SQL-скрипт.
3. Итак? Вы можете использовать параметры с обычным SQL… Я использую их все время для небольшого количества возвращаемых значений, они работают лучше, потому что вам не нужны средства чтения и / или таблицы данных и т.д.
Ответ №1:
Я не думаю, что есть «изящный» способ сделать это так, как вы его структурируете, ИМХО
- вы могли бы использовать c # try catch , чтобы перехватить исключение, возникающее при отсутствии ошибки, но обработка исключений выполняется медленно и не должна использоваться как обычный поток управляющего устройства
- вы могли бы изменить свои запросы так, чтобы они оба возвращали одинаковые имена столбцов, чтобы больше не было исключений, а идентификатор был представлен в виде строки, и у вас либо был другой столбец, который укажет вам, является ли строка идентификатором GUId или ошибкой, чтобы вы могли проанализировать или сообщить об этом соответствующим образом, либо вы пытаетесь проанализировать его и посмотреть, работает ли он
- вы могли бы изменить свои запросы, чтобы в них всегда было два столбца — строка и идентификатор GUId, а один всегда равен null, и использовать null, чтобы определить, какой тип у вас есть
- вы всегда можете выбрать как свои ошибки, так и свои идентификаторы и использовать тот факт, что sql server позволяет вам открывать несколько наборов результатов
Но реально я думаю, что я бы перестал пытаться возвращать ошибки SQL в виде результирующих наборов и просто выбрасывал их как исключения и перехватывал их в c #. Примите шаблон наличия строки, которая начинается с пустого, проверьте наличие col1 и, если его там нет, добавьте «col1 не существует» к строке, проверьте наличие col2 и, возможно, добавьте «col2 не существует».. затем, если строка не пуста, выбросьте ее, в противном случае верните свой результирующий набор. C # возникнет исключение с полезным сообщением об ошибке (и вы можете предоставить код переменной, если хотите обработать его по-другому, а не просто сообщать пользователю)
Ответ №2:
Вы можете использовать GetName
функцию SqlDataReader
using (SqlDataReader reader = await cmd.ExecuteReaderAsync(ct))
{
if (reader.HasRows)
{
while (await reader.ReadAsync(ct))
{
var colName = reader.GetName(0);
if (colName.Equals("Error_Message")
errors = reader.GetString("Error_Message");
else
id = reader.GetGuid("Id");
}
}
}