Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Базы данных под .NET > Как работать с запросами?


Автор: Fighter 5.7.2007, 05:05
Я пишу на С# после Delphi. В Delphi уже все было отточено. Есть ли в ADO.NET компонент аналогичный AdoQuery. Плюс еще я мог в AdoQuery запрос задать статически, написав его в свойстве SQL. Мог также динамически, во время выполнения программы, например:

Код

AdoQuery1.SQL.Add('select * from TAB1');
AdoQuery1.SQL.Add('where a1 > 20');


Как такое сделать в ADO.NET?

Автор: Idsa 5.7.2007, 07:43
Хм... Не знаю, правильно ли я тебя понял... но приведенный пример можно просто записать в виде строки:
Код

string query = "select * from Tab1" + "where a1 > 20";
или
string query = "select * from Tab1";
query += "where a1 > 20";

, а затем уже присвоить это значение DbComand.CommandText или DbDataAdapter.SelectCommand.

Автор: tol05 5.7.2007, 09:06
Я буду упоминать объекты SqlXXXXX, потому что с ними работаю...

Fighter, почитай про SqlCommandBuilder, удобная вещь (http://davidhayden.com/blog/dave/archive/2006/01/21/2742.aspx). кроме есть свойство SqlCommand.CommandText  (или конструктор SqlCommand), есть конструктор
Код

SqlDataAdapter (string selectCommandText, SqlConnection selectConnection)

везде можно предварительно программно генерировать строку запроса...

Только осторожно (http://subscribe.ru/archive/comp.soft.prog.dotnetgrains/200411/01120523.html)  smile

Для динамической генерации строки текста лучше использовать StringBuilder

Автор: Fighter 5.7.2007, 12:34
Спасибо, попробую. А вот еще такая тема, с запросами. Если например я использую в запросе select from то для выполнения запроса можно сделать либо AdoQuery1.Active := true либо AdoQuery1.Open. Но, если же я использую insert, update, delete то тогда тут можно использовать одну процедуру ExecSql. В ADO.NET есть что-нибудь подобное?

Автор: tol05 5.7.2007, 12:49
Цитата(Fighter @  5.7.2007,  12:34 Найти цитируемый пост)
для выполнения запроса можно сделать либо AdoQuery1.Active := true либо AdoQuery1.Open

я не очень понимаю, что делают эти команды smile
Есть в DataAdapter-е метод Update, который все команды выполняет http://msdn2.microsoft.com/en-US/library/system.data.common.dbdataadapter.update(VS.71).aspx

есть SqlCommand.CommandType - можно задать как текст или StoredProcedure (в которой. кстати ты моешь как Select, так и Insert, Delete или Update команды прописать)
Есть разные варианты выполнения команд (ExecuteNonQuery,  ExecuteReader, ExecuteScalar )
и еще много чего есть  smile 

в одном посте про ADО.NET не расскажешь. Надо читать книжки, даже не MSDN ...

Автор: Fighter 5.7.2007, 14:26
Для select используются одни процедуры, для DML другие. Есть ли такое разделение в ADO.NET?

Автор: Fighter 8.7.2007, 14:17
Все-таки, если честно, то я не разобрался. Я для себя пишу тестовый пример. БД из одной таблицы, записи требуется добавлять, удалять, изменять, очищать. Все эти действия я делал используя операторы языка. Я хотел бы делать это все чисто при помощи SQL, так как это более привычнее. Через какие компоненты нужно это делать и как нужно делать?

Автор: thomas 8.7.2007, 23:40
Fighter, 
Создаем соединение с базой и ДатаСет.
Код

Private dbCon As OleDbConnection
Private dbCmd As OleDbCommand
Private dbDa As OleDbDataAdapter
Private dbCmdBuilder As OleDbCommandBuilder
Private ds As DataSet
Private conStr As String
conStr = "provider=microsoft.jet.oledb.4.0; data source=" + "D:\vti\Margo\nwind.mdb"
dbCon = New OleDbConnection()
dbCon.ConnectionString = conStr
dbCmd = New OleDbCommand()
dbCmd.Connection = dbCon
dbDa = New OleDbDataAdapter(dbCmd)
ds = New DataSet()

А теперь пишем запрос к таблице в базе и заполнякм данными таблицу в ДатаСет
Код

sql = "SELECT * FROM tblTAbleName" 
dbCmd.CommandText = sql
dbDa.Fill(ds, tableName) ' tableName имя твоей таблицы в ДатаСет - должно отличаться от имени в Базе Данных чтоб не путаться.
DataGridView.DataSource = ds.Tables("tableName") 'увидишь что получилось в гриде.

А дальше используй команды INSRT INTO, DELETE и UPDATE для манипуляций с данными.
Код

sql = "INSERT INTO ... "  ' или пишешь тут команду на удаление .
dbCon.Open()
dbCmd.CommandText = sql
dbCmd.ExecuteNonQuery()
dbCon.Close()

Обновление можно сделать так
Код

        Dim count As Integer
        dbCmdBuilder = New OleDbCommandBuilder(dbDa)
        If ds.HasChanges(DataRowState.Modified) = True Then
            dbDa.UpdateCommand = dbCmdBuilder.GetUpdateCommand()
            Try
                count = dbDa.Update(ds, tableName)
                ds.Tables(tableName).AcceptChanges()
            Catch ex As Exception
                System.Windows.Forms.MessageBox.Show(ex.Message, "Ошибка при обновлении таблицы в ДС!")
            End Try
        End If


Ну вот коротенько. Успехов.  smile 

Автор: Fighter 9.7.2007, 04:15
Блин, большое спасибо. +1 тебе. Тему я начинаю понимать, да вроде все понятно. ТОлько вот теперь гемор с обновлением. Добавляется запись. Только я её вижу только после перезагрузки. ПОчему он не удаляет данные из DataGrid при использовании Disks.Fill?


Цитата(thomas @  8.7.2007,  23:40 Найти цитируемый пост)
А теперь пишем запрос к таблице в базе и заполнякм данными таблицу в ДатаСеткод VB.NET1:2:3:4:sql = "SELECT * FROM tblTAbleName" dbCmd.CommandText = sqldbDa.Fill(ds, tableName) ' tableName имя твоей таблицы в ДатаСет - должно отличаться от имени в Базе Данных чтоб не путаться.DataGridView.DataSource = ds.Tables("tableName") 'увидишь что получилось в гриде.


И здесь тоже есть вопрос. Как здесь вяжется dbCmd с остальными компонентами. ну, данные выбрались, а куда они делись?

Автор: thomas 9.7.2007, 22:39
Fighter, 

Цитата

Как здесь вяжется dbCmd с остальными компонентами. ну, данные выбрались, а куда они делись? 


Привет!
Ты когда создавал ДатаАдаптер 

dbDa = New OleDbDataAdapter(dbCmd)

перед этим определил только свойство   соединения  dbCmd.Connection = dbCon
А теперь перед выполнением метода Fill() определил и текст команды dbCmd.CommandText = sql.
А метод Fill() ДатаАдаптера создает таблицу в ДатаСете и заполняет ее данными, полученными на основании запроса.

Меняя sql и имена таблиц ты можешь напихать в ДатаСет сколько угодно таблиц используя  один ДатаАдаптер. 

Автор: Fighter 10.7.2007, 00:19
Цитата(thomas @  9.7.2007,  22:39 Найти цитируемый пост)
Ты когда создавал ДатаАдаптер dbDa = New OleDbDataAdapter(dbCmd)перед этим определил только свойство   соединения  dbCmd.Connection = dbConА теперь перед выполнением метода Fill() определил и текст команды dbCmd.CommandText = sql.А метод Fill() ДатаАдаптера создает таблицу в ДатаСете и заполняет ее данными, полученными на основании запроса.Меняя sql и имена таблиц ты можешь напихать в ДатаСет сколько угодно таблиц используя  один ДатаАдаптер. 



А это я понимаю работает в начале работы прогарммы, перед загрузкой.
Я в общем, можно сказать понял все это. Я через oledbCommand записи вставлял в таблицу (пока что изменять не пробовал, но потом попробую, думаю должно работать). А вот как обновлять, не знаю.

Автор: thomas 10.7.2007, 08:22
Fighter, 
смотри три поста выше 

Автор: Fighter 10.7.2007, 09:01
Код

        Dim count As Integer
        dbCmdBuilder = New OleDbCommandBuilder(dbDa)
        If ds.HasChanges(DataRowState.Modified) = True Then
            dbDa.UpdateCommand = dbCmdBuilder.GetUpdateCommand()
            Try
                count = dbDa.Update(ds, tableName)
                ds.Tables(tableName).AcceptChanges()
            Catch ex As Exception
                System.Windows.Forms.MessageBox.Show(ex.Message, "Ошибка при обновлении таблицы в ДС!")
            End Try
        End If

Я так понимаю эта часть?

Если да, то можно рассказать про каждую строчку (если есть время конечно)? Чтобы на будущее было ясно что зачем, а не так, что нужно заучить этот код.

Автор: tol05 10.7.2007, 10:06
создаем построитель команд (чтоб самому не писать и не выполнять OleDbCommand вручную)
требуем чтобы построитель построил команду и присвоил ее команде обновления адаптера
обновляем
                 ds.Tables(tableName).AcceptChanges()  я бы убрал, потому что это лишняя операция - dbDa.Update его вызывает сама ( http://forum.vingrad.ru/index.php?showtopic=150459&view=findpost&p=1129662  и там еще ссылка на более ранний пост есть)
Если какая-то проблема - о ней сообщаем мессаджем

Автор: emmanuil 10.7.2007, 10:17
Надеюсь будет понятно.
Код

        Dim count As Integer
        dbCmdBuilder = New OleDbCommandBuilder(dbDa) // создаем построитель команд. Он сам формирует запрос для изменения набора
        If ds.HasChanges(DataRowState.Modified) = True Then // проверяем, есть ли измененные записи
            dbDa.UpdateCommand = dbCmdBuilder.GetUpdateCommand() // адаптеру присваем UpdateCommand, созданный построителем команд
            Try
                count = dbDa.Update(ds, tableName) // производим обновление и получаем количество реально обновленных строк в базе
                ds.Tables(tableName).AcceptChanges() // в локальном наборе принимаем все изменения
            Catch ex As Exception
                System.Windows.Forms.MessageBox.Show(ex.Message, "Ошибка при обновлении таблицы в ДС!")
            End Try
        End If

Автор: Fighter 12.7.2007, 02:51
Блин, извините, совсем уж лол, себя не узнаю (хотя это мож после Delphi). Опять я загнулся на добавлении. Вот код:

Код

                String str;
                str = "INSERT INTO Disks" + Convert.ToChar(13);
                str += "(Disc_Name, Disc_Have, Disc_Type)" + Convert.ToChar(13);
                str += "values(" + "'" + addDisk.textBox1.Text + "', ";
                str += "'" + addDisk.textBox2.Text + "', ";
                str += "'" + addDisk.textBox3.Text + "')";
                if (oleDbConnection1.State == ConnectionState.Closed)
                {
                    oleDbConnection1.Open();
                }
                oleDbCommand1.CommandText = str;
                oleDbCommand1.ExecuteNonQuery();
                oleDbConnection1.Close();
                ds1.Disks.AcceptChanges();



Да, здесь без обновления. Но, мне хотя бы пока без обновления чтобы это все добавлялось в базу. Что же здесь не так (смысл надо оставить тем же, добавление через запросы) в реализации? Да, все объекты oledbCommand, oleDbDataAdapter - я уж пока что мышкой таскаю на форму. Пока что хватает. 

Автор: emmanuil 12.7.2007, 05:25
Все должно работать, а в чем конкретно проблемма, что за ошибка?
Код

            using (OleDbConnection oleDbConnection1 = new OleDbConnection(<строка подключения>))
            {
                using (OleDbCommand oleDbCommand1 = oleDbConnection1.CreateCommand())
                {
                    StringBuilder sb = new StringBuilder("INSERT INTO Disks\n");
                    sb.Append("(Disc_Name, Disc_Have, Disc_Type)\n");
                    sb.Append("values(" + "'" + addDisk.textBox1.Text + "', ");
                    sb.Append("'" + addDisk.textBox2.Text + "', ");
                    sb.Append("'" + addDisk.textBox3.Text + "')");

                    oleDbCommand1.CommandText = sb.ToString();
                    oleDbConnection1.Open();
                    oleDbCommand1.ExecuteNonQuery();
                    //ds1.Disks.AcceptChanges(); // это тут не нужно, так как ты добавляешь запросом, чтобы отобразить изменения в наборе, нужно его переоткрыть
                }
            }
        }

addDisk - это внешняя форма? Если да, то лучше через свойства, а не делать компоненты public.
\n - можно не писать, а вместо этого можно сделать пробел.

Автор: emmanuil 12.7.2007, 05:49
Если сервер у тебя Sql Server 2005 то используй пространство имен System.Data.SqlClient (мож для 2000-го тож подойдет, сам не пробовал).
Не рекомендую собирать sql код в коде программы, напиши лучше хранимку с параметрами и через нее работай (личное мнение). Если решишь, помогу с параметрами в ADO.NET. Я сам раньше писал на Delphi. технология ADO и ADO.NET кардинально отличаются друг от друга. В ADO.NET, все наборы данных не имеют постоянного коннекта с базой. Они локальные! А в ADO, они все связаны напрямую с базой. Поэтому в ADO.NET больше писанины для работы с базой. 

Автор: Fighter 12.7.2007, 06:13
Цитата(emmanuil @  12.7.2007,  05:25 Найти цитируемый пост)
Все должно работать, а в чем конкретно проблемма, что за ошибка?



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

Добавлено через 40 секунд
Хм... Извините, что-то меня щас на мысль толкнуло. Я думаю, что все работает. Щас проверю.

Добавлено через 9 минут и 35 секунд
Да, все работает. Я при создании коннекта выбрал, чтобы база у меня вместе с компиляцией копировалась в папку с экзэшником. Да, щас добавляет. Ну, буду мучить обновление. 

Кстати, обновление, которое было написано выше я пробовал и он все равно таблицу не обновлял. Я программу не закрывал и поэтому он новую копию базы не делал, следовательно он должен был обновить.

Я вот что думаю, может быть дело такое. В моей таблице Disks есть поля (Disc_id, DIsc_Name, Disc_have, Disc_Type). Я при настройке DataAdapter'a при создании Select'a я выбрал только поля Disc_Name, Disc_Have, Disc_Type, поля Disc_id - я не выбрал. Из-за этого он при создании смог сгенерить только SelectCommand. А при обновлении используется OleDbCommandBuilder.GetUpdateCommand(). Мож он из-за этого неправильно формирует команду на обновление. 

Автор: Fighter 12.7.2007, 06:34
Итак, совершенно случайно "нарвался" на рабочий вариант кода. Вот как оно вышло:

Код

                String str;
                str = "INSERT INTO Disks" + Convert.ToChar(13);
                str += "(Disc_Name, Disc_Have, Disc_Type)" + Convert.ToChar(13);
                str += "values(" + "'" + addDisk.textBox1.Text + "', ";
                str += "'" + addDisk.textBox2.Text + "', ";
                str += "'" + addDisk.textBox3.Text + "')";
                if (oleDbConnection1.State == ConnectionState.Closed)
                {
                    oleDbConnection1.Open();
                }
                oleDbCommand1.CommandText = str;
                oleDbCommand1.ExecuteNonQuery();
                oleDbConnection1.Close();
                ds1.Disks.Clear(); // Здесь Disks - класс таблицы дисков в наборе данных ds1
                Disks.Fill(ds1, "Disks"); // Здесь Disks - это oleDbDataAdapter


Если возможно объяснение вот этого, почему же этот вариант полностью работает. Добавляет запись в саму таблицу, да и еще DataGridView обновляет. Во, чудеса какие-то. Лана, ща дальше буду пробовать этот C#.

Добавлено через 46 секунд
Цитата(emmanuil @  12.7.2007,  05:49 Найти цитируемый пост)
Если решишь, помогу с параметрами в ADO.NET.


Спасибо, как доберусь - думаю топик создам, буду ждать пока ответишь. 

Автор: emmanuil 12.7.2007, 07:25
тут интересны только две строчки.
Совет: Если у тебя одна таблица, то не используй DataSet, а используй DataTable.
Код

ds1.Disks.Clear(); // Здесь Disks - класс таблицы дисков в наборе данных ds1
Disks.Fill(ds1, "Disks"); // Здесь Disks - это oleDbDataAdapter

ds1.Disks.Clear(); - очищает все записи в наборе
Disks.Fill(ds1, "Disks"); - заполняет занова нобор данных из базы
так как к гриду у тебя подцеплена эта таблица, то и в гриде данные отображаются

Добавлено через 3 минуты и 50 секунд
Цитата(emmanuil @  12.7.2007,  03:25 Найти цитируемый пост)
чтобы отобразить изменения в наборе, нужно его переоткрыть

Вот те две строчки, как раз это и делают

Автор: Fighter 12.7.2007, 14:32
Цитата(emmanuil @  12.7.2007,  07:25 Найти цитируемый пост)
ds1.Disks.Clear(); - очищает все записи в набореDisks.Fill(ds1, "Disks"); - заполняет занова нобор данных из базытак как к гриду у тебя подцеплена эта таблица, то и в гриде данные отображаются


Т.е. он очищает записи не в самой базе, а в наборе. А потом заново туда данные заливает. Ясно. Спасибо.
Вроде все DML операции пашут. Надо будет щас попробовать выборку из 2 таблиц с ограничениями сделать. 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)