ошибка преобразования при преобразовании даты и / или времени из символьной строки при чтении из файла

#c# #sql-server

#c# #sql-сервер

Вопрос:

Я знаю, что этот вопрос был опубликован в stackoverflow в разных формах, но мне не удалось решить мою проблему. Я пытаюсь вставить в базу данных sql Server данные, считанные из текстового файла. Ранее я вставлял данные в базу данных в формате ‘2014-02-02’, поэтому я не думаю, что это отсюда. Мой текстовый файл выглядит следующим образом :

 1213 3 2013-01-03 2013-03-03
1263 2 2014-01-01 2014-01-10
 

и мой код:

         private void importComandăToolStripMenuItem_Click(object sender, EventArgs e)
         {
            string cale = Application.StartupPath;
            OpenFileDialog ofd = new OpenFileDialog();
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                cale = ofd.FileName;
                System.IO.StreamReader sr = new System.IO.StreamReader(cale);
                string linie = null;
                while ((linie = sr.ReadLine()) != null)
                {
                        string comanda = sr.ReadLine();
                        string[] vcmd = comanda.Split(' ');

                        foreach (string cmd in vcmd)
                        {
                             SqlConnection conn = new SqlConnection("server=localhost;"  
    "Trusted_Connection=yes;"  
    "database=erp; "  
    "connection timeout=30");
                SqlCommand cmd1 = new SqlCommand();
                cmd1.CommandText = "Insert into [erp].[dbo].[Comenzi] values(" Int32.Parse(cmd[0].ToString()) "," Int32.Parse(cmd[1].ToString()) ",'" cmd[2].ToString() "','" cmd[3].ToString() "');";
                cmd1.CommandType = CommandType.Text;
                cmd1.Connection = conn;
                conn.Open();
                cmd1.ExecuteNonQuery();
                conn.Close();

                        }

                    }
                MessageBox.Show("Comanda inserată");

                }

            else
                MessageBox.Show("Inserare eșuată");
            }
        }
 

Есть предложения?

Комментарии:

1. почему бы не проанализировать данные и не выполнить преобразование строки в datetime в c #, а затем передать правильный sqlparameter в ваш оператор insert?

Ответ №1:

Первая проблема — это две даты в вашем файле. Если они выражены в формате, принятом вашими настройками локали, преобразования может быть достаточно. Однако ваш код, который пытается обновить базу данных, содержит много ошибок.

Я пытался их исправить.

  • Первый. используйте инструкцию using, чтобы правильно закрыть соединение, когда вы это сделаете
  • Второй. используйте параметризованный запрос для передачи данных в вашу базу данных. Конкатенация строк подвержена ошибкам из-за плохого синтаксического анализа и открыта для взломов sql-инъекций.
  • Третье. откройте соединение непосредственно перед входом в цикл и создайте команду с ее параметрами с некоторыми фиктивными значениями. Внутри цикла измените значение параметров на фактическое значение и выполните запрос
  • Четвертое. Разделение строки создает массив, и вам нужно использовать ЧЕТЫРЕ элемента массива, а не несистематические элементы cmd одной строковой переменной
  • Пятое. Вы читаете строку два раза для каждого цикла. Если у вас нет пустой строки в каждой строке данных, вам следует удалить строку чтения внутри цикла

.

  private void importComandăToolStripMenuItem_Click(object sender, EventArgs e)
 {
    string cale = Application.StartupPath;
    OpenFileDialog ofd = new OpenFileDialog();
    if (ofd.ShowDialog() == DialogResult.OK)
    {
        cale = ofd.FileName;
        System.IO.StreamReader sr = new System.IO.StreamReader(cale);
        using(SqlConnection conn = new SqlConnection("server=localhost;"  
                                 "Trusted_Connection=yes;"  
                                 "database=erp; "  
                                 "connection timeout=30"))
        using(SqlCommand cmd1 = new SqlCommand(@"Insert into [erp].[dbo].[Comenzi] values 
                                                @p1, @p2, @p3, @p4", conn)
        {
            conn.Open();
            cmd1.Parameters.AddWithValue("@p1", 0);
            cmd1.Parameters.AddWithValue("@p2", 0);
            cmd1.Parameters.AddWithValue("@p3", DateTime.MinValue);
            cmd1.Parameters.AddWithValue("@p4", DateTime.MinValue);
            string comanda = null;
            while ((comanda = sr.ReadLine()) != null)
            {
                string[] vcmd = comanda.Split(' ');
                cmd1.Parameters["@p1"].Value = Convert.ToInt32(vcmd[0]));
                cmd1.Parameters["@p2"].Value = Convert.ToInt32(vcmd[1]));
                cmd1.Parameters["@p3"].Value = Convert.ToDateTime(vcmd[2]));
                cmd1.Parameters["@p4"].Value = Convert.ToDateTime(vcmd[3]));
                cmd1.ExecuteNonQuery();
            }
        }
    }
}
 

Комментарии:

1. Почему необходимо добавлять значения по умолчанию? Также нужно ли нам приводить строки к соответствующим типам данных при добавлении значений в параметр?

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

3. Параметры имеют тип данных, который должен соответствовать типу данных полей в базе данных. Опять же, я использовал AddWithValue , поэтому тип данных для параметра определяется типом данных значения, переданного для создания. Я полагаю, что datatable содержит два столбца integer и два столбца datetime, поэтому я использовал соответствующий параметр для этих столбцов, чтобы избежать возможных ошибок преобразования. Конечно, если предположение неверно, то нам нужно изменить этот код

4. Большое вам спасибо, теперь я понимаю.

5. Я изменил свой ответ в соответствии с вашим подходом. Спасибо.

Ответ №2:

удалите foreach.

 private void importComandaToolStripMenuItem_Click(object sender, EventArgs e)
         {
            string cale = Application.StartupPath;
            OpenFileDialog ofd = new OpenFileDialog();
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                cale = ofd.FileName;
                System.IO.StreamReader sr = new System.IO.StreamReader(cale);
                string linie = null;
                while ((linie = sr.ReadLine()) != null)
                {
                        string comanda = sr.ReadLine();
                        string[] vcmd = comanda.Split(' ');

                        //foreach (string cmd in vcmd)
                        //{
                             SqlConnection conn = new SqlConnection("server=localhost;"  
    "Trusted_Connection=yes;"  
    "database=erp; "  
    "connection timeout=30");
                SqlCommand cmd1 = new SqlCommand();
                cmd1.CommandText = "Insert into [erp].[dbo].[Comenzi] values(" vcmd[0] "," vcmd[1] ",'" vcmd[2] "','" vcmd[3] "');";
                cmd1.CommandType = CommandType.Text;
                cmd1.Connection = conn;
                conn.Open();
                cmd1.ExecuteNonQuery();
                conn.Close();

                        //}

                    }
                MessageBox.Show("Comanda inserata");

                }

            else
                MessageBox.Show("Inserare e?uata");
            }
        }
 

Ответ №3:

Если cmd является строкой, cmd[0] выдаст вам первый символ в строке. Я не думаю, что это то, чего вы хотите. Вероятно, вы имели в виду vcmd [0], что означает, что вам не нужен цикл.

Ответ №4:

Ответ Стива четко объясняет все проблемы, существующие в вашем коде.

Когда вы делаете это:

  string[] vcmd = comanda.Split(' ');
 

Вы получаете массив строк, подобный этому string[] array

  string[] vcmd = {"1213", "3", "2013-01-03", "2013-03-03" };
 

Приведенный ниже цикл on string[] предоставит вам каждую строку в cmd переменной:

  foreach (string cmd in vcmd)
 {
     //here cmd values on each iteration

     // first iteration = "1213"
     // second iteration = "3"
     // third iteration = "2013-01-03"
     // fourth iteration = "2013-03-03"
  }
 

Лучший подход может быть:

  1. Прочитайте все строки файлов за один раз.
  2. Создать SqlConnection в начале метода.
  3. Использовать SqlCommand Parameters .
  4. Используйте using инструкцию.

Пример (не проверялся):

 private void importComandăToolStripMenuItem_Click(object sender, EventArgs e)
{
   string connstring = @"server=localhost; 
                         Trusted_Connection=yes; 
                         database=erp; connection timeout=30";

   string cale = GetFileName();

   if(cale != string.Empty)
   {
      IEnumerable<string> arrLines = File.ReadLines(cale);
      string sql = @"Insert into [erp].[dbo].[Comenzi] values 
                                            (@P1, @P2, @P3, @P4)";
      using (SqlConnection conn = new SqlConnection(connstring))
      {
          conn.Open();
          using (SqlCommand cmd = new SqlCommand(sql, conn))
          {
              cmd.Parameters.AddWithValue("@P1", 0);
              cmd.Parameters.AddWithValue("@P2", 0);
              cmd.Parameters.AddWithValue("@P3", DateTime.MinValue);
              cmd.Parameters.AddWithValue("@P4", DateTime.MinValue);

              foreach (string sLine in arrLines)
              {
                 string[] vcmd = sLine.Split(' ');
                 cmd.Parameters["@P1"].Value = Convert.ToInt32(vcmd[0]);
                 cmd.Parameters["@P2"].Value = Convert.ToInt32(vcmd[1]);
                 cmd.Parameters["@P3"].Value = Convert.ToDateTime(vcmd[2]);
                 cmd.Parameters["@P4"].Value = Convert.ToDateTime(vcmd[3]);
                 cmd.ExecuteNonQuery();
              }
          }
       }
       //check can be added based on int returned by ExecuteNonQuery
       MessageBox.Show("Comanda inserată");
    }                
}

//method to show open file dialog return filename or empty
private string GetFileName()
{
    OpenFileDialog ofd = new OpenFileDialog();

    if (ofd.ShowDialog() == DialogResult.OK)
         return ofd.FileName;
    else
    {
         MessageBox.Show("Inserare eșuată");
         return string.Empty;
     }
}
 

Комментарии:

1. Спасибо. Это работает. в нем есть несколько синтаксических ошибок, таких как: вы должны добавить круглые скобки в команду insert string sql = @"Insert into [erp].[dbo].[Comenzi] values (@P1, @P2, @P3, @P4)"; и при добавлении параметров удалить одну из круглых скобок, чтобы было похоже cmd.Parameters["@P1"].Value = Convert.ToInt32(vcmd[0]);

2. Спасибо. Я исправил обе проблемы с синтаксисом.