#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"
}
Лучший подход может быть:
- Прочитайте все строки файлов за один раз.
- Создать
SqlConnection
в начале метода. - Использовать
SqlCommand Parameters
. - Используйте
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. Спасибо. Я исправил обе проблемы с синтаксисом.