Я читаю данные из базы данных Oracle в таблицу данных, конвертирую их в JSON, и кажется, что он преобразует int, который равен 1335 в строке таблицы данных, в «1335.0», что вызывает проблему при десериализации.
Столбцы определены в базе данных как:
REQUEST_ID NUMBER(20,0)
(Частичный) запрос выглядит так:
SELECT req.REQUEST_ID AS \"uniqueId\",
Я вызываю API, который возвращает результат этого запроса в таблицу данных C#:
DataTable dt = ODCException.GetError();
Когда я проверяю строки «dt», я вижу, что uniqueId равен 1335, 1336 и т. д.
Я также определил класс для хранения каждого отдельного объекта как:
public class jsonObject
{
public int uniqueId { get; set; }
....
}
Когда я сериализую "dt":
string JSONresult = JsonConvert.SerializeObject(dt);
и проверьте JSONresult, который я вижу:
[{"uniqueId":1335.0,...}, {"uniqueId":1336.0,...}]
И позже, когда я пытаюсь десериализовать:
List<jsonObject> loErrorData = JsonConvert.DeserializeObject<IEnumerable<jsonObject>>(JSONresult).ToList();
Я получил:
{"Input string '1335.0' is not a valid integer. Path '[0].uniqueId', line 1, position 19."}
Мне нужно иметь возможность получить результат, в котором "uniqueId" имеет значение int, а не строку.
Обновлять
Мне удалось решить проблему следующим образом. Несмотря на то, что рассматриваемый столбец объявлен в базе данных как NUMBER (28,0), т. Е. Без десятичной точки, я продолжал получать «1335.0» вместо 1335 для столбца «uniqueId».
Так:
public static DataTable GetTCErrors()
{
DataSet ds = oRespository.GetErrors(); // Get data from DB
DataTable dt2 = new DataTable();
if (ds.Tables.Count > 0)
{
DataTable dt = new DataTable();
dt = ds.Tables[0];
dt2.Columns.Add("uniqueId", typeof(Int32));
dt2.Load(dt.CreateDataReader(), LoadOption.OverwriteChanges);
}
return dt2;
}
Теперь, когда я использую следующее, я получаю 1335, 1336,... как значения uniqueId в JSONresult:
DataTable dt = ODCException.GetTCErrors();
string JSONresult = JsonConvert.SerializeObject(dt);
JsonConvert не будет сериализовать int с десятичной точкой. Пожалуйста, покажите скрипку, демонстрирующую проблему. Возможно, dt на самом деле DataTable, а не jsonObject?
Что такое dt? Какой это тип? DataTable? Покажите, пожалуйста, как вы получаете данные из базы данных?
@mxmissile Я не могу удалить десятичную дробь, это то, что возвращает JsonConvert.
@ gunr2171 Я создал скрипку, но не могу ее воспроизвести! dotnetfiddle.net/OgG6py, Не знаю, где искать проблему. Я тоже обновил вопрос.
Может ли тот, кто закрыл это, снова открыть его, так как я отредактировал вопрос и включил ссылку на скрипку? Мне нужна помощь, чтобы решить эту проблему.
@Charlieface ответил на мое намерение удалить десятичную дробь, вот ваш ответ.
Вот ваша реплика dotnetfiddle.net/9RbgPb Я проголосовал за повторное открытие. Решение в основном состоит в том, чтобы изменить запрос, чтобы он читался SELECT CAST(req.REQUEST_ID AS int) AS uniqueId
Не уверен, что сказать, правда. Я показал столбец базы данных, объявленный как (NUMBER), набор данных, полученный в результате запроса, показывает значения int для «uniqueId» как 1335 и 1336. И сразу после JsconConvert.Serialize я получаю «1335.0» и «1336.0». Как вы видите в скрипке, которую я опубликовал, я не могу воспроизвести ее в скрипке, что еще больше расстраивает. Только не знаю, где искать проблему.
Моя ссылка на репродукцию показывает, что столбец с типом decimal вызовет эту ошибку. Если столбец хранится в базе данных как NUMBER, то он будет преобразован в decimal, а не int на стороне C#, поэтому вам нужно выполнить приведение.
@Charlieface, спасибо. Кастинг в запросе Oracle не помог, та же ошибка. Кроме того, в Oracle этот столбец уже NUMBER (28,0), без десятичных знаков. Ваша рабочий пример указывает на то, что десериализация в список объектов, где «uniqueId» определяется как int, вызывает ошибку. Я не понимаю, как значение столбца с данными, которое является int (1335), преобразуется в «1335.0» после вызова JsonConvert.Serialize.
Я нашел обходной путь, который решил проблему. Я добавил в часть вопроса «Обновить».





Тот факт, что столбец объявлен NUMERIC(28,0), не преобразует его в int на стороне C#. Только если это INTEGER, то так и будет.
Так что вы можете просто использовать его в Oracle
SELECT CAST(req.REQUEST_ID AS INTEGER) AS "uniqueId",
Сказав это, ваш другой вариант - использовать его на стороне С#. Вы уже предоставили один из способов сделать это, сначала добавив столбец с typeof(int) в DataTable.
Но, честно говоря, если вы создаете объектную модель, вам следует просто отказаться от DataTable и напрямую использовать ридер.
public static List<jsonObject> GetTCErrors()
{
var list = new List<jsonObject>();
using var conn = new OracleConnection(YourConnString);
using var comm = new OracleCommand(YourQuery, conn);
// parameters here
conn.Open();
using var reader = comm.ExecuteReader();
while (reader.Read())
{
list.Add(new jsonObject
{
uniqueId = (int)(decimal)reader["uniqueId"], // notice the double-cast
}
}
return list;
}
Вы также можете использовать Dapper, чтобы сделать большую часть этого автоматически, хотя я не уверен, как он справляется с подобным кастингом.
Вы абсолютно правы. Я должен был сделать это в первую очередь и избавить себя от большого горя. Вывод всего этого идет к брокеру Kafka, и они требуют, чтобы данные были в формате JSON. Когда я делаю это в Oracle 19c+, я просто использую json_object, и все готово. Именно с Oracle до 19c мне приходится выполнять это преобразование JSON вручную.
Я использовал ваш метод использования считывателя вместо набора данных. Пометил ваш ответ как ответ. Спасибо за помощь.
Это работает, если вы удалите десятичную дробь?