Проблемы с POST и PUT в таблице с числовыми значениями, разделенными запятыми

У меня возникают проблемы с POST и PUT для моего бэкэнда. Соответствующую структуру таблицы можно увидеть здесь

DROP TABLE IF EXISTS coordinate;
CREATE TABLE coordinate
(
   id                    int(10) NOT NULL auto_increment,
   longitude             double(8,4) NOT NULL,
   latitude              double(8,4) NOT NULL,
   measurementId         int(10) default NULL,
   PRIMARY KEY (id),
   FOREIGN KEY (measurementId) 
        REFERENCES measurement (id)
        ON DELETE CASCADE
);

У него есть соответствующий Model, который выглядит так

public class Coordinate
{
    public Coordinate()
    {

    }

    public int ID { get; set; }

    public double Latitude { get; set; }

    public double Longitude { get; set; }

    public int MeasurementId { get; set; }

    ...
}

Я пытаюсь вставить числовые значения в coordinate вот так:

sql = "UPDATE coordinate SET longitude = '" + coordinate.Longitude + "," + " latitude = " + coordinate.Latitude + "," + " measurementId = " + coordinate.MeasurementId + "' WHERE id = " + id.ToString();

Обратите внимание на включение одинарной скобки перед двойной скобкой после longitude = '" и + "' WHERE ....

Когда я запускаю это с помощью отладчика, строка sql создается следующим образом:

sql = "UPDATE coordinate SET longitude = '55,6, latitude = 70,33, measurementId = 2' WHERE id = 2'

И мой бэкэнд выдает следующую ошибку:

{
 "Message": "An error has occurred.",
 "ExceptionMessage": "Data truncated for column 'longitude' at row 1",
 "ExceptionType": "MySql.Data.MySqlClient.MySqlException",
 ...
}

Я предполагаю, что строка sql построена неправильно из-за включения одинарной скобки, поэтому я удаляю ее и создаю новую строку sql следующим образом:

sql = "UPDATE coordinate SET longitude = " + coordinate.Longitude + "," + " latitude = " + coordinate.Latitude + "," + " measurementId = " + coordinate.MeasurementId + " WHERE id = " + id.ToString();

Обратите внимание на удаление одиночной скобки ' в тех местах, где она была раньше. Теперь в отладчике строка sql строится так:

sql = "UPDATE coordinate SET longitude 55,6 latitude = 70,33, measurementId = 2 WHERE id = 2"

У меня сложилось впечатление, что числовые значения должны быть разделены ., а не ,, что может быть причиной того, что серверная часть теперь выдает эту ошибку:

{
 "Message": "An error has occurred.",
 "ExceptionMessage": "You have an error in your SQL syntax; check the manual 
 that corresponds to your MySQL server version for the right syntax to use 
 near '6, latitude = 70,33, measurementId = 2 WHERE id = 2' at line 1",
}

Я немного не понимаю, как обрабатывать вставку числовых значений в мою базу данных. Любая помощь горячо приветствуется.

Вам нужно переписать это как параметризованный запрос, чтобы исправить имеющуюся у вас уязвимость SQL Injection, тогда вам не понадобится конкатенация строк, чтобы избежать несбалансированных кавычек, отсутствующих символов и т. д. Это также устранит несколько проблем с форматированием.

Alex K. 29.05.2019 12:42

Используйте параметры. У вас не будет проблем с синтаксисом

Crowcoder 29.05.2019 12:42

@АлексК. Хорошо, рассмотрим это.

kdhansen 29.05.2019 12:46
Этот (старый) ответ предполагает, что MySql не поддерживает неанглийские десятичные точки в операторах INSERT. Однако параметризованные запросы мощь решают эту проблему, как и @AlexK. предложено - определенно стоит попробовать, поскольку теоретически параметры устраняют двусмысленность, описанную в связанном ответе (и которую вы видите здесь)
Diado 29.05.2019 13:29
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
105
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Попробуйте следующее.

sql = "UPDATE coordinate SET longitude = '" + coordinate.Longitude + "', latitude = '" + coordinate.Latitude + "', measurementId = '" + coordinate.MeasurementId + "' WHERE id = " + id.ToString();

@ShyamVemula Нет, данные усекаются (первая ошибка, которую я выделил в своем вопросе)

kdhansen 29.05.2019 12:49

@ShyamVemula ошибка усечения данных означает, что запрос выполнен, чего он не сделал бы, если бы была синтаксическая ошибка.

Crowcoder 29.05.2019 12:49

каковы datatypes столбцы долготы и широты?.

Shyam Vemula 29.05.2019 12:51

@ShyamVemula double, как указано в моем вопросе в самом верху.

kdhansen 29.05.2019 12:52

Эти столбцы имеют тип данных double, а данные, которые вы передаете, — 55,6 и 70,33. ALTER типы данных столбца в char(20)

Shyam Vemula 29.05.2019 13:00

@ShyamVemula Я знаю, что они double, и нет, я прохожу нет55,6 - это преобразование происходит где-то в цепочке. Данные должны храниться в базе данных как правильное числовое значение, а не как char.

kdhansen 29.05.2019 13:02

Может быть, попробовать следующее. Я думаю, проблема в том, что вам нужно использовать '.' вместо ',', чтобы сделать десятичные значения понятными для SQL. Имейте в виду, что когда вы пытаетесь вернуть долготу/широту, она будет возвращена в виде строки.

Я не проверял это, но попробуйте.

using System.Globalization;
public class Coordinate
{
    NumberFormatInfo nfi = new NumberFormatInfo();

    public Coordinate()
    {
        nfi.NumberDecimalSeparator = ".";
    }

    public int ID { get; set; }

    public double Latitude { get; set; }

    public double Longitude { get; set; }

    public int MeasurementId { get; set; }

    public string GetLatitudeComma()
    {
        return this.Latitude.ToString(nfi);
    }

    public string GetLongitudeComma()
    {
        return this.Longitude.ToString(nfi);
    }
}

А также...

sql = "UPDATE coordinate SET longitude = '" + coordinate.GetLongitudeComma() + "," + " latitude = " + coordinate.GetLatitudeComma()+ "," + " measurementId = " + coordinate.MeasurementId + "' WHERE id = " + id.ToString();

Возвращает строку из свойств, введенных как double? А также условие переполнения стека.

Crowcoder 29.05.2019 13:06

Хорошо, внес изменения, чтобы он действительно скомпилировался, проблема только в запятых, удалите их, и вы золотой. Вы можете сделать это по-другому с помощью 'coordinate.Latitude.ToString().Replace(',','.')', но это может привести к грязному коду.

DubDub 29.05.2019 13:48

@DubDub Немного хакерский, но сработало :-) Спасибо!

kdhansen 29.05.2019 15:55

заменять «ОБНОВЛЕНИЕ координат SET долгота = '55,6, широта = 70,33, MeasurementId = 2' ГДЕ id = 2' к «ОБНОВЛЕНИЕ координат SET: долгота = ‘55,6’, широта = ‘70,33’, MeasurementId = ‘2’, ГДЕ id = ‘2’

заменить "," на "." (от 55,6 до 55,6) sql не читает и не записывает число с ","

Ответ принят как подходящий

Как указано в комментариях к моему вопросу, использование параметризованного запроса решило проблему с дополнительным преимуществом защиты SQL-запроса. Хотя ответ DubDub был хорошим обходным путем, следующее решает его более масштабируемым и безопасным способом.

SQL-запрос теперь выглядит так:

 string sql = "UPDATE coordinate SET longitude = @Longitude, latitude = @Latitude, measurementId = @MeasurementId WHERE id = @ID";

 List<MySqlParameter> parameters = SqlFactory.CreateParametersFor(coordinate);

 cmd = SqlFactory.CreateParameterizedQuery(sql, parameters, conn);

 cmd.Parameters.Add(ID);

 await cmd.ExecuteNonQueryAsync();

Где CreateParametersFor() и CreateParameterizedQuery() реализованы так:

public static MySqlCommand CreateParameterizedQuery(string sql, List<MySqlParameter> parameters, MySqlConnection connection)
    {
        MySqlCommand cmd = new MySqlCommand(sql, connection);
        foreach (MySqlParameter parameter in parameters) cmd.Parameters.Add(parameter);
        return cmd;
    }

    public static List<MySqlParameter> CreateParametersFor(Coordinate coordinate)
    {
        List<MySqlParameter> parameters = new List<MySqlParameter>();

        MySqlParameter latitude = new MySqlParameter()
        {
            ParameterName = "@Latitude",
            Value = coordinate.Latitude
        };

        MySqlParameter longitude = new MySqlParameter()
        {
            ParameterName = "@Longitude",
            Value = coordinate.Longitude
        };

        MySqlParameter measurementId = new MySqlParameter()
        {
            ParameterName = "@MeasurementId",
            Value = coordinate.MeasurementId
        };

        parameters.Add(latitude);
        parameters.Add(longitude);
        parameters.Add(measurementId);

        return parameters;
    }

Бум, это выглядит намного лучше в конце. Я рекомендую изменить заголовок вопроса, чтобы включить где-то «десятичные значения, разделенные запятыми», потому что это было проблемой. Кроме того, если вы заинтересованы в эффективности/безопасности/масштабируемости кода, возможно, проведите некоторое исследование хранимых процедур, чтобы вы могли отделить свой бизнес-уровень от уровня доступа к данным. (например, обычно не идеально иметь sql в бэкэнде страниц, он должен быть в своих собственных классах или иным образом)

DubDub 30.05.2019 10:25

@DubDub Я посмотрю на это. Я обновил название вопроса, чтобы отразить фактическую проблему. Спасибо за вашу помощь :-)

kdhansen 30.05.2019 13:13

Другие вопросы по теме