#c# #sql #winforms
#c# #sql #winforms
Вопрос:
Недавно я начал программировать на c # (в мае этого года), и я считаю, что лучше всего учиться, работая с кодом. это приложение http://www.c-sharpcorner.com/UploadFile/satisharveti/ActiveApplicationWatcher01252007024921AM/ActiveApplicationWatcher.aspx. Я пытаюсь воссоздать его, однако мой будет сохранять информацию в базе данных sql (в этом тоже есть что-то новое). У меня возникли некоторые проблемы с кодированием, поскольку он не выполняет то, что я ожидаю от него. Это основной код, который я использую.
private void GetTotalTimer()
{
//This gets the window that a user has open
SqlConnection RConn = new SqlConnection(@"server=ANDILE-PC;Initial Catalog=Log Records;Integrated Security=SSPI;");
string Connstring = RConn.ToString();
DateTime now = DateTime.Now;
IntPtr hwnd = APIFunc.getforegroundWindow();
Int32 pid = APIFunc.GetWindowProcessID(hwnd);
Process p = Process.GetProcessById(pid);
appName = p.ProcessName;
string time = now.ToString();
const int nChars = 256;
int handle = 0;
StringBuilder Buff = new StringBuilder(nChars);
handle = GetForegroundWindow();
appltitle = APIFunc.ActiveApplTitle().Trim().Replace("", "");
string queryString = "Select Top 1[Window Title] FROM [TimerLogs]";
using (RConn)
{
using (SqlCommand command = RConn.CreateCommand())
{
command.CommandText = queryString;
RConn.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
string windowtitle = reader["Window Title"].ToString();
if (appltitle != windowtitle)
{
endTime = DateTime.Now;
appduration = endTime.Subtract(startTime);
cmd = new SqlCommand("insert into [TimerLogs] values (@time,@appName,@appltitle,@Elapsed_Time,@userName)", RConn);
cmd.Parameters.AddWithValue("@time", time);
cmd.Parameters.AddWithValue("@appName", appName);
cmd.Parameters.AddWithValue("@appltitle", appltitle);
cmd.Parameters.AddWithValue("@Elapsed_Time", appduration.ToString());
cmd.Parameters.AddWithValue("@userName", userName);
cmd.ExecuteNonQuery();
RConn.Close();
}
}
reader.Close();
}
RConn.Close();
}
}
}
К сожалению, это результат.
данные сохраняются не так, как я ожидаю. Что я делаю не так, я думал, что с помощью sql Reader он сначала проверит значение и сохранит только в том случае, если они не совпадают, однако он сохраняет, есть совпадение или нет.
мой читатель возвращает «{System.Data.SqlClient.SqlDataReader}» вместо данных в таблице
Комментарии:
1. Вам нужно научиться использовать функции отладки вашей IDE. Установите точку останова, затем пошагово просмотрите код построчно и посмотрите, что он делает.
2. ваш if (appltitle != читатель. Условие toString()) всегда верно, проверьте его правильно
3. Я новичок как в c #, так и в sql, поэтому вместо того, чтобы просто голосовать против, как насчет использования конструктивной критики, потому что ваши голоса ни в чем не помогают, я хочу понять этот язык, но, пытаясь все, что я получаю, — это отрицательные голоса. Как это поможет, если я допустил ошибку, укажите на это вслепую — голосование никому не помогает
4. Один совет, который я могу вам дать (не имеющий прямого отношения к вашей проблеме), — это избегать
try
иcatch
на данный момент. Пока вы разрабатываете код, вам нужно разрешить эти исключения, чтобы вы могли их видеть и исправлять, чтобы они не возникали в дикой природе.5. Основная причина, по которой я их использую, заключается в том, что код запускается по таймеру, и когда я использовал его в первый раз, он чуть не разбил мой компьютер с ошибками
Ответ №1:
Хорошо, у нас здесь возникают три проблемы. Давайте сначала сосредоточимся на вашей ошибке:
Вы используете reader.ToString()
, но этот метод делает не то, что вы думаете.
Посмотрите его здесь -> http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldatareader.aspx (вы можете перейти на эту страницу и похожие страницы, поместив курсор внутрь имени типа, а затем нажав «F1»).
Итак, вместо вашего ‘toString ()’ вам нужно получить доступ к полю, которое вы хотите сравнить, безопасным для типов способом, используя reader.GetString(0)
.
Вторая проблема: внутри вашего else if
блока вы дважды закрываете SqlDataReader. Это вызвало бы исключение.
Теперь перейдем к третьей проблеме:
Всегда используйте один объект подключения для каждого запроса SQL. Соединения SQL кэшируются в .NET, поэтому вам не нужно беспокоиться о потерях времени, и при этом вам также не нужно постоянно проверять состояние вашего соединения.
Чтобы упростить задачу, позвольте мне показать вам магию использования операторов:
using (SqlConnection myConn = new SqlConnection(connstring))
{
myConn.Open();
// execute first statement
}
using (SqlConnection myConn2 = new SqlConnection(connstring))
{
myConn2.Open();
// execute second statement
}
Частью инструкции using является объявление объекта, который вы хотите использовать. Объект должен иметь тип ‘IDisposable’. Внутри оператора using объект обрабатывается как «обычный» объект, по крайней мере, по большей части. Вы не можете изменить его ссылку (это означает, что вы не можете назначить новое SqlConnection для myConn2), но это все.
Все становится интереснее, когда вы оставляете оператор using . Независимо от того, как вы его оставите (оператор return внутри, возникло необработанное исключение или программа просто продолжит работу после выполнения всего внутри оператора using), объект будет удален. И в случае SqlConnection или SqlDataReader его Close()
метод также будет вызываться как часть реализации Dispose() .
Комментарии:
1. Хорошо, но я хочу получить последнее значение в столбце заголовка окна, я думал, что вы используете sqldatareader для получения этой информации, я делаю это неправильно?
2. а? Здесь мы говорим о столбцах, а не о строках. Ваш оператор возвращает только одну строку и одно поле. Чтобы получить доступ к первой строке, вы уже сделали все необходимое (вызываете
Read()
один раз), теперь вам нужно получить доступ к первому столбцу для этой записи.3. ну, последней строкой в заголовке окна будет одно значение, которое я пытаюсь использовать для чтения, но после использования точек останова я обнаружил, что оно не возвращает значения, как я думал
4. @Broken_Code стоп, ты что-то путаешь
(или я неправильно это понимаю). Выполните свой оператор SQL на вашем SQL server, если он вернет то, что должен вернуть, все должно быть в порядке). Если нет, пожалуйста, отредактируйте свой ответ и добавьте свой текущий исходный код.
5. Я получаю последнее значение, как и должен, когда выполняю его на сервере sql
Ответ №2:
Проблема: вы сравниваете appltitle
(я думаю, строковую переменную) с объектом SqlDataReader . которое всегда дает вам not equal, и поскольку вы инвертируете свой результат, он всегда будет истинным, следовательно, он сохраняет данные в data независимо от ситуации.
Решение: вам нужно проверить appltitle
переменную с помощью соответствующего столбца из инструкции SELECT.
reader[0]
выдает вам window title
данные из базы данных (указанные в инструкции SELECT)
Замените это:
if (appltitle != reader.ToString())
С помощью этого:
if (appltitle != reader[0].ToString())
Комментарии:
1. Чем это отличается от [0], я попробую, просто хочу понять
2. @Broken_Code: reader[0] выдает вам первое значение параметра из инструкции SELECT, то есть
window title
проверьте мой отредактированный ответ.3. Я пытался использовать reader [0]. toString результаты, хотя и не изменились. Я также использовал точки останова, и для моего значения по-прежнему указано System.Data.SqlClient.SqlDataReader вместо последнего значения строки заголовка окна
4. @SudhakarTillapudi хотя это возможно сделать таким образом, вы всегда должны пытаться использовать средства доступа к типу для получения значения. В этом случае
.GetString(0);
это был бы самый простой способ сделать это.