Как я могу обновить datagridview на основе дубликата ключа?
Привет,
У меня есть метод, который вставляет информацию в таблицу(посещаемость), которая подключена к datagridview(dg).Мой вопрос будет заключаться в том, как я могу определить дубликат ключа, чтобы обновить datagridview при обнаружении дубликата ключа?Я нашел несколько примеров в интернете относительно использования счетчика, и вот как сейчас выглядит мой метод:
private void btnSave_Click(object sender, EventArgs e) { var result = checkCourse(); if(result==true) { using (var cn = new SqlConnection(connstr)) { SqlCommand checkData = new SqlCommand("SELECT COUNT(dateArrival) FROM AttendanceList WHERE SN = @Id and Attending=0", cn); checkData.Parameters.AddWithValue("@Id", txtStudentId.Text); cn.Open(); int Exist = (int)checkData.ExecuteScalar(); cn.Close(); if (Exist % 2 == 0) { try { using (var cnn = new SqlConnection(connstr)) { var query = "Insert into AttendanceList(SN,sNr,fName,lName,dateArrival,Attending,Departed,CourseId)Values(@SN,@sNr,@fName,@lName,@dateArrival,@Attending,@Departed,@ClassId) "; using (var cmd = new SqlCommand(query, cnn)) { try { string Studentquery = "select sNr, fName,lName from RegisterStudent WHERE (SN = @SN)"; using (var Student = new SqlCommand(Studentquery, cnn)) { Student.Parameters.AddWithValue("@SN", txtStudentId.Text); cnn.Open(); cn.Open(); dr = Student.ExecuteReader(); if (dr.HasRows == true) { while (dr.Read()) { if (dr.HasRows == true) { cmd.Parameters.AddWithValue("@sNr", dr["sNr"].ToString()); cmd.Parameters.AddWithValue("@fName", dr["fName"].ToString()); cmd.Parameters.AddWithValue("@lName", dr["lName"].ToString()); } } } } } catch (Exception ex) { // write exception info to log or anything else MessageBox.Show(ex.Message); cmd.Parameters.AddWithValue("@fName", ""); cmd.Parameters.AddWithValue("@lName", ""); cmd.Parameters.AddWithValue("@sNr", 0); } cmd.Parameters.AddWithValue("@SN", txtStudentId.Text); cmd.Parameters.AddWithValue("@dateArrival", dtArrival.Text); cmd.Parameters.AddWithValue("@ClassId", cmbClassId.SelectedValue.ToString()); cmd.Parameters.AddWithValue("@Departed", 0); cmd.Parameters.AddWithValue("@Attending", 1); dr.Close(); cmd.ExecuteNonQuery(); cn.Close(); cnn.Close(); dg.Update(); dg.Refresh(); LoadData(); Clr(); } } } catch (Exception ex) { // write exception info to log or anything else MessageBox.Show(ex.Message); } } // else { using (var cnn = new SqlConnection(connstr)) { int count = (int)checkData.ExecuteScalar(); if (count>0) { checkData = new SqlCommand( "update AttendanceList set Departed=@Departed, dateDeparture=@dateDeparture where sNr=(SELECT MAX (sNr) FROM AttendanceList) and SN=@SN", cn); cn.Open(); checkData.Parameters.AddWithValue("@SN", txtStudentId.Text); checkData.Parameters.AddWithValue("@dateDeparture", dtArrival.Text); checkData.Parameters.AddWithValue("@Departed", 1); checkData.ExecuteNonQuery(); cn.Close(); dg.Update(); dg.Refresh(); Clr(); LoadData(); Clr(); } } } } } }
Когда ПК обнаруживается в первый раз,записи
"Insert into AttendanceList(SN,sNr,fName,lName,dateArrival,Attending,Departed,CourseId)Values(@SN,@sNr,@fName,@lName,@dateArrival,@Attending,@Departed,@ClassId) ";вставляются в базу данных,но когда я снова ввожу тот же ПК,я получаю ошибку, что есть нарушение ПК.Часть кода
else { using (var cnn = new SqlConnection(connstr)) { int count = (int)checkData.ExecuteScalar(); if (count>0) { checkData = new SqlCommand( "update AttendanceList set Departed=@Departed, dateDeparture=@dateDeparture where SN=@SN", cn); cn.Open(); checkData.Parameters.AddWithValue("@SN", txtStudentId.Text); checkData.Parameters.AddWithValue("@dateDeparture", dtArrival.Text); checkData.Parameters.AddWithValue("@Departed", 1); checkData.ExecuteNonQuery(); cn.Close(); dg.Update(); dg.Refresh(); Clr(); LoadData(); Clr(); } } }проверяет, есть ли дубликат ключа с графом.Если это так,то он должен обновить остальную информацию.CheckData приходит из метода
private bool checkCourse() { using (var cn = new SqlConnection(connstr)) { SqlCommand checkData = new SqlCommand("SELECT * FROM StudentCourses WHERE StudentId ='"+txtStudentId.Text+"' and courseid='"+ cmbClassId.SelectedValue.ToString() + "'", cn); cn.Open(); SqlDataReader sdr = checkData.ExecuteReader(); if (sdr.Read()) { return true; } cn.Close(); return false; } }который проверяет, находится ли студент с этим ПК на определенном курсе(но это прекрасно работает). Почему мой подход неверен?Как я могу сделать так, чтобы он работал так, как ожидалось?Пожалуйста, дайте мне знать, если есть какая-либо информация, которая должна быть предоставлена.Заранее благодарю вас!
Что я уже пробовал:
в C# обновление если запись не существует, то вставить новую запись - переполнение стека[^]
https://stackoverflow.com/questions/23191951/how-to-avoid-insert-duplicate-record-in-sql-server-using-windows-form-in-c-sharp[^]
Mike V Baker
Похоже, что в вашей логике есть возможность, когда запись может существовать, но все равно не пройти тест. Посмотреть на это:
SqlCommand checkData = new SqlCommand("SELECT COUNT(dateArrival) FROM AttendanceList WHERE SN = @Id and Attending=0", cn);
Ваши критерии здесь-SN = @Id *и* Attending=0. Поэтому, если посещаемость не равна 0, она не будет возвращена. Я предполагаю, что ваш первичный ключ-это просто SN, так что вы здесь. Вы попытаетесь вставить новую запись с SN, которая уже есть. Я не уверен насчет использования модуля.
if (Exist %2 == 0)Итак, вы проверяете, является ли количество записей четным числом? Кроме того... теперь, когда я думаю об этом, я не вижу здесь ничего о конкретном классе. Есть студент, и посещаемость... где спецификация в вашем запросе о том, какой класс посещается? Я вижу CourseId в запросе insert, но не вижу, чтобы он использовался в проверке для поиска предыдущей записи.
Вы упомянули во вступлении, что эти данные были подключены к сетке данных. Но имена элементов управления предполагают отдельные элементы управления, а не строки и столбцы в сетке.
Eliza Maria
Спасибо, что ответили.Я вижу,что,поскольку вы не понимаете того, что я пытаюсь выяснить, Вам также трудно дать мне объяснение.Итак,это моя логика в коде:
Запрос SqlCommand checkData = new SqlCommand("SELECT COUNT(dateArrival) FROM AttendanceList WHERE SN = @Id and Attending=0", cn);
inserts the data of the student into the AttendanceList table which is then displayed in the datagridview.Selecting the count in dateArrival is basically just a count that states that the Student is registered in RegisterStudent table with the info required,then the info from registerStudent will be inserted into the AttendanceList if the Serial nr from the textbox matches the serialnr in RegisterStudent(basically the record will be added based on dateTime).The Atteding=0 is logical that it has to be 0,because otherwise it means that the student is already attending that specific course.Indeed,the parameter ClassId and CourseID don't match but there are one and the same because parameter ClassId defines CourseId.There's no specification about what class is attending the student,but what course he's attending.Also,I don't understand what you mean by "It looks like there's a possibility in your logic where a record can exist but still fail the test."because this is the query for inserting data into AttendanceList,the other query checkData = new SqlCommand(
"обновление установить AttendanceList отошел=@отошел, dateDeparture=@dateDeparture где СН=@СН", СП);
спицы.Открыть();
это для обновления списка посещаемости с помощью dateDeparture и Departed,что означает, что когда текстовое поле еще раз идентифицирует тот же серийный номер, оно должно обновить dateDeparture и Departed.Я надеюсь,что вы понимаете мою логику,потому что та часть, которую вы упомянули в своих комментариях, работает отлично, а часть обновления сложна.Пожалуйста, дайте мне знать, если вы понимаете, почему эта часть не работает.С наилучшими пожеланиями!
Mike V Baker
Спасибо за дополнительную информацию. Я не уверен что это помогло :) Я постараюсь сосредоточиться только на дубликате ключевой части. Одно можно сказать наверняка: вы не можете вставить запись с тем же PK, что и другая запись. Это противоречит назначению первичного ключа. Так что же такое PK таблицы AttendanceList? Если это SN + CourseId, то у вас может быть только одна запись для этого студента и этого курса.
Что такое sNr? Играет ли это какую-то роль в ПК? Является ли сочетание этих трех вещей всегда уникальной ценностью?
В какой-то момент Вы сказали, что "else" проверяет, есть ли дубликат ключа с графом. Однако это "еще" проистекает из if (Exist % 2 == 0), который проверяет, есть ли у вас четное количество записей. Что делать, если в этой таблице есть записи для других курсов? Он, по-видимому, не включает в себя все значения, необходимые для PK, поэтому он может не исключать некоторые записи, которые он должен был бы иметь.
Я только что заметил еще одну вещь. В разделе "вставка" вы устанавливаете departed=0 и attending=1. В разделе "Обновление" вы устанавливаете departed=1, но не устанавливаете attending=0. Будет ли посещение всегда 1 раз, когда они посетили в аренду один раз?
Eliza Maria
Thank you for your response.Attending and departed are 2 separate flags.When I insert into the AttendanceList-which has SN(which is the student nr of the student)the PK-it inserts the dateArrival(with datetime)and updates the Attending bite to 1,leaving the Departed one 0.When the SN will be inserted the second time,it will update the dateDeparture and Departed flag will be 1 along with the Attending flag.I have tried with the syntax "ON duplicate key update" but this didn't work.Also I have used the count to determine if there is a duplicate key,in that key it should update.My problem is why is not working the updating part based on the duplicate key?Is my approach wrong?
С уважением
Mike V Baker
Итак, вы говорите, что ПК в таблице AttendanceList - это SN. Только SN, никакие другие поля не являются частью первичного ключа? Это будет означать, что у вас может быть только одна запись в таблице AttendanceList для этого студента. Студент не может посещать более одного класса одновременно, никогда. Это транзакционная таблица, где она используется только в течение ограниченного времени, а записи удаляются, когда вы закончите процесс? Если PK-это просто SN, то использование подсчета для определения наличия нескольких записей никогда не должно возвращать > 1, потому что вы не можете вставить две записи с одним и тем же PK.
Eliza Maria
Привет, Майк,Спасибо за твой ответ.Мне удалось решить свою проблему, удалив Attending=0 из count, где я храню значения в БД.Это была единственная проблема, которая мешала мне достичь желаемого результата.В любом случае спасибо Вам за ваше время и поддержку.Желаю вам всего наилучшего!
Mike V Baker
Привет, Элиза, я рад слышать, что ты нашла решение. Удачи вам с остальной частью вашего проекта.