Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Работа с DataAdapter  (Прочитано 23725 раз)
0 Пользователей и 1 Гость смотрят эту тему.
tumanovalex
Помогающий

ru
Offline Offline

« : 11-04-2013 16:22 » 

Никак не получается связь между таблицами и установка значения idContact в таблице Phone:
Код:
    private void Form1_Load(object sender, EventArgs e)
    {
      OleDbConnection connection = new OleDbConnection();
      connection.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=.\\AdoStudy.mdb";
      try
      {
        connection.Open();
      }
      catch
      {
        MessageBox.Show("Ошибка соединения с базой данных AdoStudy.mdb");
        Application.Exit();
      }
      OleDbCommand command = connection.CreateCommand();
      OleDbDataAdapter dataAdapter = new OleDbDataAdapter();
      command.CommandText = "SELECT *FROM Contacts";
      dataAdapter.SelectCommand = command;
      dataAdapter.FillSchema(myData, SchemaType.Source, "Contacts");
      command.CommandText = "SELECT *FROM Phone";
      dataAdapter.SelectCommand = command;
      dataAdapter.FillSchema(myData, SchemaType.Source, "Phone");
      DataColumn[] keys = new DataColumn[1];
      myData.Tables["Contacts"].Columns["idContact"].Unique = true;
      keys[0] = myData.Tables["Contacts"].Columns["idContact"];
      myData.Tables["Contacts"].PrimaryKey = keys;
      DataRelation rl = new DataRelation("relat", myData.Tables["Contacts"].Columns["idContact"],
                        myData.Tables["Phone"].Columns["idContact"], true);
      myData.Relations.Add(rl);
      command.CommandText = "SELECT *FROM Contacts";
      dataAdapter.SelectCommand = command;
      dataAdapter.Fill(myData, "Contacts");
      command.CommandText = "SELECT *FROM Phone";
      dataAdapter.Fill(myData, "Phone");
      myData.Tables["Contacts"].Columns["idContact"].Unique = true;
      myData.Tables["Phone"].Columns["Phone"].Caption = "Номер телефона";
      dgvContacts.DataSource = myData.Tables["Contacts"];
      dgvPhone.DataSource = myData.Tables["Phone"];
    }
Хотелось бы с этим разобраться.

* AdoStudy3.zip (28.94 Кб - загружено 763 раз.)
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 11-04-2013 17:59 » 

tumanovalex, а как ты себе представляешь результат?
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
tumanovalex
Помогающий

ru
Offline Offline

« Ответ #2 : 12-04-2013 11:56 » 

Представляю его так: при установке выделения на строку таблицы Contacts при вводе нового телефона в поле idContacts таблицы Phone появлялось бы значение из поля idContacts выбранной строки контакта.
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 12-04-2013 16:42 » 

tumanovalex, и где код визуальной части? где связь источников данных с элементами формы?
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
tumanovalex
Помогающий

ru
Offline Offline

« Ответ #4 : 12-04-2013 18:17 » 

Как я понял, код визуальной части и жесткая связь источников данных с элементами формы нужна для типизированного DataSet. А я заполняю контролы с помощью нетипизированного DataSet и DataAdapter.
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #5 : 12-04-2013 21:20 » 

tumanovalex, проблема в том, что ты говоришь о каких-то вещах, которые считаешь очевидными для всех. Это не так. Хотя бы мог усомниться, потому что ты сам точно не знаешь, что ты говоришь, и насколько правильно ты говоришь и понимаешь. А телепатов тут не водится.

Поэтому или ты рассказываешь подробно и обстоятельно, или я не знаю, чем тебе помогать. Тот код, что ты привёл, лишь создаёт структуру данных. Из этого никаких проблем не следует.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
tumanovalex
Помогающий

ru
Offline Offline

« Ответ #6 : 13-04-2013 06:27 » 

Я думал, что из прикрепленного проекта понятно, что у меня не получается. Попробую объяснить:
1. Я создаю 2 DataGridView. В загрузке формы создаю код, который, как я думал, обеспечивает следующее:
- загружает схему таблиц из базы данных Access;
- создает отношение между таблицами;
- устанавливает источник данных для каждого из DataGridView.
2. В результате я получаю заполненные DataGridView с колонками, заголовки которых соответствуют названиям полей в таблицах базы данных.
3. Поля iContact таблиц Contact и Phone связаны отношением один ко многим в базе данных. Я думал, что при загруженных схемах и установленном отношении между таблицами в случае ввода телефона, относящегося к контакту, в поле ввода iContact таблицы Phone DataAdapter будет установлено значение поля iContact активного контакта из DataGridView1.  Кроме того, я думал, что при выборе нужного контакта в таблице DataGridView1 в таблице телефонов DataGridView2 будут показываться только телефоны, относящиеся к выбранному контакту.
 Однако получается следующее:
- при выборе контакта видны все телефоны, а не только относящиеся к данному контакту;
- при вводе нового телефона правильно устанавливается поле счетчика для записи телефона, но номер контакта в записи остается пустым.
в общем хотелось бы сделать так при вводе номера так, как при вводе в Access нового номера телефона при щелчке на знаке "+". Прикрепляю новый проект, в котором введены номера телефонов и из которого, наверное, будет все ясно.

* AdoStudy4.ZIP (28.9 Кб - загружено 778 раз.)
« Последнее редактирование: 13-04-2013 06:36 от tumanovalex » Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #7 : 13-04-2013 10:41 » 

tumanovalex, ну во-первых, твои grid ничего не знают о наличии связи. И никаким шаманством оно само по себе не догадается. Хотя бы по той причине, что количество и характер связей в dataset могут быть самыми разнообразными. Для правильного binding нужно помимо datasource указать datamember - на что ориентироваться grid'у. Для master это будет имя datatable, для detail это будет имя datarelation.

Во-вторых, datarelation настраивает grid на работу не с таблицей, а с отфильтрованным представлением таблицы, откуда следует, что операции добавления новых элементов в таблицу становятся менее тривиальными. Как минимум, нужно позаботиться о значениях по-умолчанию для связующего ключа, да и autoincrement поля тоже перестают работать.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
tumanovalex
Помогающий

ru
Offline Offline

« Ответ #8 : 15-04-2013 06:01 » 

Вот так вроде бы получается так, как я хотел:
Код:
namespace ADOstudy
{
  public partial class Form1 : Form
  {
    private DataSet myData;

    public Form1()
    {
      InitializeComponent();
      myData = new DataSet();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
      OleDbConnection connection = new OleDbConnection();
      connection.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=.\\AdoStudy.mdb";
      try
      {
        connection.Open();
      }
      catch
      {
        MessageBox.Show("Ошибка соединения с базой данных AdoStudy.mdb");
        Application.Exit();
      }
      OleDbCommand command = connection.CreateCommand();
      OleDbDataAdapter dataAdapter = new OleDbDataAdapter();
      command.CommandText = "SELECT *FROM Contacts";
      dataAdapter.SelectCommand = command;
      dataAdapter.FillSchema(myData, SchemaType.Source, "Contacts");
      command.CommandText = "SELECT *FROM Phone";
      dataAdapter.SelectCommand = command;
      dataAdapter.FillSchema(myData, SchemaType.Source, "Phone");
      command.CommandText = "SELECT *FROM Contacts";
      dataAdapter.SelectCommand = command;
      dataAdapter.Fill(myData, "Contacts");
      command.CommandText = "SELECT *FROM Phone";
      dataAdapter.Fill(myData, "Phone");
      DataRelation rl = new DataRelation("relat", myData.Tables["Contacts"].Columns["idContact"],
                        myData.Tables["Phone"].Columns["idContact"], true);
      myData.Relations.Add(rl);
      BindingSource bsParent;
      BindingSource bsChild;
      bsParent = new BindingSource();
      bsChild = new BindingSource();
      bsParent.DataSource = myData;
      bsParent.DataMember = "Contacts";
      bsChild.DataSource = bsParent;
      bsChild.DataMember = "relat";
      dgvContacts.DataSource = bsParent;
      dgvPhone.DataSource = bsChild;
    }
Не уверен, что в коде нет лишних элементов. Посмотрите, пожалуйста, правильно ли я понял Ваши разъяснения и нет ли чего в коде лишнего. Проект прикрепляю

* AdoStudy5.zip (28.87 Кб - загружено 772 раз.)
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #9 : 15-04-2013 08:51 » 

tumanovalex, ну в начале там зачем-то настраивается запрос, потом затирается новым, потом опять восстанавливается. А binding и так есть в grid, т.е. свойства datamember и datasource можно присваивать прямо в grid без промежуточных объектов.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
tumanovalex
Помогающий

ru
Offline Offline

« Ответ #10 : 16-04-2013 05:58 » 

Если не использовать схему данных, то не работает установка номера в счетчиках:
Код:
    private void Form1_Load(object sender, EventArgs e)
    {
      OleDbConnection connection = new OleDbConnection();
      connection.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=.\\AdoStudy.mdb";
      try
      {
        connection.Open();
      }
      catch
      {
        MessageBox.Show("Ошибка соединения с базой данных AdoStudy.mdb");
        Application.Exit();
      }
      OleDbCommand command = connection.CreateCommand();
      OleDbDataAdapter dataAdapter = new OleDbDataAdapter();
      //command.CommandText = "SELECT *FROM Contacts";
      //dataAdapter.SelectCommand = command;
      //dataAdapter.FillSchema(myData, SchemaType.Source, "Contacts");
      //command.CommandText = "SELECT *FROM Phone";
      //dataAdapter.SelectCommand = command;
      //dataAdapter.FillSchema(myData, SchemaType.Source, "Phone");
      command.CommandText = "SELECT *FROM Contacts";
      dataAdapter.SelectCommand = command;
      dataAdapter.Fill(myData, "Contacts");
      command.CommandText = "SELECT *FROM Phone";
      dataAdapter.Fill(myData, "Phone");
      DataRelation rl = new DataRelation("relat", myData.Tables["Contacts"].Columns["idContact"],
                        myData.Tables["Phone"].Columns["idContact"], true);
      myData.Relations.Add(rl);
      BindingSource bsParent = new BindingSource();
      BindingSource bsChild = new BindingSource();
      bsParent.DataSource = myData;
      bsParent.DataMember = "Contacts";
      bsChild.DataSource = bsParent;
      bsChild.DataMember = "relat";
      dgvContacts.DataSource = bsParent;
      dgvPhone.DataSource = bsChild;
    }
Если загрузить схемы, то счетчики работают. А для того, чтобы загрузить схемы, нужен запрос. Вот из-за чего у меня появился лишний код. Подскажите, пожалуйста, как в моем случае без лишнего кода сделать так, чтобы была связь двух таблиц и правильно работал счетчик.
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #11 : 16-04-2013 08:21 » 

tumanovalex, не увидел разницы с предыдущим, кроме комментариев. Я и не говорил, что схемы не грузить. Я только не понимаю, почему это не делать сразу с fill, а надо по 2 раза перенастраивать dataadapter.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
tumanovalex
Помогающий

ru
Offline Offline

« Ответ #12 : 16-04-2013 14:37 » 

Спасибо за ответ. Попробовал сделать так, как Вы советовали (разместил загрузку схемы рядом с fill), все заработало нормально. Теперь возникла задача внести в базу данных изменения, которые я сделал в формах. Подскажите, пожалуйста, как это можно сделать. По имеющейся у меня книге Малик Сахил "Microsoft ADO.NET 2.0 для профессионалов" я разобраться не смог.
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #13 : 16-04-2013 20:11 » 

tumanovalex, dataadapter имеет все 4 команды работы с данными. Поскольку определён лишь select, то и программа работает лишь на чтение из базы. Если доопределить остальные команды insert, update, delete, то будет полная синхронизация с базой. Однако нужно вручную вызывать dataadapter.update, который выгружает данные из dataset в базу. Вызывать его можно, например, по событию изменения в grid или в datatable.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
tumanovalex
Помогающий

ru
Offline Offline

« Ответ #14 : 17-04-2013 15:13 » 

Попробовал сделать Update для таблицы контактов:
Код:
    private void Form1_Load(object sender, EventArgs e)
    {
      OleDbConnection connection = new OleDbConnection();
      connection.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=.\\AdoStudy.mdb";
      try
      {
        connection.Open();
      }
      catch
      {
        MessageBox.Show("Ошибка соединения с базой данных AdoStudy.mdb");
        Application.Exit();
      }
      cmd = connection.CreateCommand();
      cmd.CommandText = "SELECT *FROM Contacts";
      da.SelectCommand = cmd;
      da.FillSchema(myData, SchemaType.Source, "Contacts");
      da.Fill(myData, "Contacts");
      cmd.CommandText = "SELECT *FROM Phone";
      da.SelectCommand = cmd;
      da.FillSchema(myData, SchemaType.Source, "Phone");
      da.Fill(myData, "Phone");
      DataRelation rl = new DataRelation("relat", myData.Tables["Contacts"].Columns["idContact"],
                        myData.Tables["Phone"].Columns["idContact"], true);
      myData.Relations.Add(rl);
      bsParent.DataSource = myData;
      bsParent.DataMember = "Contacts";
      bsChild.DataSource = bsParent;
      bsChild.DataMember = "relat";
      dgvContacts.DataSource = bsParent;
      dgvPhone.DataSource = bsChild;
      daInsert();
      daUpdate();
      daDelete();
     }

    private void testBaseBindingNavigatorSaveItem_Click(object sender, EventArgs e)
    {
       da.Update(myData.Tables["Contacts"]);
    }

    private void daInsert()
    {
      cmd.CommandText = "INSERT INTO Contacts " +
                        " (idContact, Person, Birthday, YearBirthday) VALUES " +
                        " (@idContact, @Person, @Birthday, @YearBirthday)";
      da.InsertCommand = cmd;
      pc = da.InsertCommand.Parameters;
      pc.Add("@idContact", OleDbType.Integer, 0, "idContact");
      pc.Add("@Person", OleDbType.VarChar, 0, "Person");
      pc.Add("@Birthday", OleDbType.DBDate, 0, "Birthday");
      pc.Add("@YearBirthday", OleDbType.Integer, 0, "YearBirthday");
    }

    private void daUpdate()
    {
      cmd.CommandText = "UPDATE Contacts " +
                        " SET idContact = @idContact_New, Person = @Person_New, " +
                        " Birthday = @Birthday_New, YearBirthday = @YearBirthday_New " +
                        " WHERE idContact = @idContact_Old AND Person = @Person_Old AND " +
                               " Birthday = @Birthday_Old AND YearBirthday = @YearBirthday_Old";
      da.UpdateCommand = cmd;
      pc = da.UpdateCommand.Parameters;
      pc.Add("@idContact_New", OleDbType.Integer, 0, "idContact");
      pc.Add("@Person_New", OleDbType.VarChar, 0, "Person");
      pc.Add("@Birthday_New", OleDbType.DBDate, 0, "Birthday");
      pc.Add("@YearBirthday_New", OleDbType.Integer, 0, "YearBirthday");
      p = pc.Add("@idContact_Old", OleDbType.Integer, 0, "idContact");
      p.SourceVersion = DataRowVersion.Original;
      p = pc.Add("@Person_Old", OleDbType.VarChar, 0, "Person");
      p.SourceVersion = DataRowVersion.Original;
      p = pc.Add("@Birthday_Old", OleDbType.DBDate, 0, "Birthday");
      p.SourceVersion = DataRowVersion.Original;
      p = pc.Add("@YearBirthday_Old", OleDbType.Integer, 0, "YearBirthday");
    }

    private void daDelete()
    {
      cmd.CommandText = "DELETE FROM Contacts " +
                        " WHERE idContact = @idContact AND Person = @Person AND " +
                               " Birthday = @Birthday AND YearBirthday = @YearBirthday";
      da.DeleteCommand = cmd;
      pc = da.DeleteCommand.Parameters;
      p = pc.Add("@idContact", OleDbType.Integer, 0, "idContact");
      p.SourceVersion = DataRowVersion.Original;
      p = pc.Add("@Person", OleDbType.VarChar, 0, "Person");
      p.SourceVersion = DataRowVersion.Original;
      p = pc.Add("@Birthday", OleDbType.DBDate, 0, "Birthday");
      p.SourceVersion = DataRowVersion.Original;
      p = pc.Add("@YearBirthday", OleDbType.Integer, 0, "YearBirthday");
      p.SourceVersion = DataRowVersion.Original;
    }
При попытке сохранить данные сообщений об ошибке не появляется, но и данные в базу mdb не вносятся. Подскажите, пожалуйста, в чем ошибка.

* AdoStudy.zip (29.73 Кб - загружено 792 раз.)
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #15 : 19-04-2013 08:09 » 

tumanovalex, во-первых, меня не радует каждый раз выгружать проект и ковыряться в коде. Это работа разработчика - искать ошибки. Получается, что я за тебя выполняю твою работу по отладке.

Т.е. позиция: "У меня тут не работает проект - разбирайтесь в моём творении" - неправильная позиция. Пользуйся отладчиком, изучай язык, среду и Framework. Причём ни на форуме, ни книжки тебя не научат, где и что в студии смотреть - это всецело твой личный expirience, наработанный самостоятельно.

Во-вторых по содержанию. Ты не понимаешь, что делает тот код, который ты пишешь. В твоём решении все команды dataadapter содержат DELETE - т.е. самую последнюю присвоенную. По той причине, что ты вместо создания объектов command всё пишешь в единственный объект. Поскольку классы - ссылочные типы, копируются только ссылки на команду, но не сами объекты. Программист должен смотреть на объекты, а не только на переменные в коде - писать осознанно и вдумчиво.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
tumanovalex
Помогающий

ru
Offline Offline

« Ответ #16 : 19-04-2013 14:20 » 

Справедливые замечания. Но без помощи на форумах мне вряд ли удастся разобраться. Нет коллектива программистов, который бы мог помочь, работа с программированием не связана, это хобби. Буду пытаться разбираться дальше, но, видимо, уже без Вашей помощи. Спасибо за советы. 
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #17 : 19-04-2013 17:11 » 

tumanovalex, советы разработчиков как правило позитивны: как что-то сделать, какой подход/архитектуру/технологию/шаблон проектирования применить; бывают пояснения о том, как что-то работает или устроено.

Но отладка, ловля ошибок - это повседневная работа, которая занимает 50-100% рабочего времени. Потому что что-то плохо документировано, или разработчик не знает, как чем-то пользоваться, и пишет методом проб и ошибок. Поскольку это почти у всех так, приходить к другим с "найди мне, где у меня ошибка" - это именно перекладывание своей работы на другого.

"Начинающий" - тут не оправдание. Любой начинающий проходит такой этап, на котором его главное приобретение: научиться искать ошибки и читать документацию самостоятельно.

Да, это некомфортное состояние: лбом об стену. Не работает, и не знаешь, что делать, и не знаешь, когда это закончится, и непродуктивно, и скучно. Но такая вот работа, особенно на неизведанных территориях с незнакомыми технологиями. Но это не повод перекладывать свою работу на других за просто так. Это повод продумать план исследования проблемы и наметить гипотезы возникновения ошибки, продумать способы проверки, протоколирования работы машины, проанализировать полученные результаты проверок, отобрать перспективные гипотезы, определить нужные изменения. И так шаг за шагом, проблема за проблемой.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
tumanovalex
Помогающий

ru
Offline Offline

« Ответ #18 : 19-04-2013 18:21 » 

Тогда спрошу по-другому. Я упростил структуру базы данных и написал новый код:
Код:
private void daUpdate()
{
  OleDbParameter p;
  OleDbParameterCollection pc;
  // insert
  da.InsertCommand = new OleDbCommand();
  pc = da.InsertCommand.Parameters;
  p = pc.Add("@id", OleDbType.Integer);
  p.SourceVersion = DataRowVersion.Current;
  p = pc.Add("@txt", OleDbType.VarChar);
  p.SourceVersion = DataRowVersion.Current;
  p = pc.Add("@dt", OleDbType.DBDate);
  p.SourceVersion = DataRowVersion.Current;
  p = pc.Add("@num", OleDbType.Integer);
  p.SourceVersion = DataRowVersion.Current;
  cmd.CommandText = "INSERT INTO tbl1(id, txt, dt, num) VALUES(@id, @txt, @dt, @num)";
  da.InsertCommand = cmd;
  // update
  da.UpdateCommand = new OleDbCommand();
  pc = da.UpdateCommand.Parameters;
  p = pc.Add("@id_new", OleDbType.Integer);
  p.SourceVersion = DataRowVersion.Current;
  p = pc.Add("@txt_new", OleDbType.VarChar);
  p.SourceVersion = DataRowVersion.Current;
  p = pc.Add("@dt_new", OleDbType.DBDate);
  p.SourceVersion = DataRowVersion.Current;
  p = pc.Add("@num_new", OleDbType.Integer);
  p.SourceVersion = DataRowVersion.Current;
  p = pc.Add("@id_old", OleDbType.Integer);
  p.SourceVersion = DataRowVersion.Original;
  p = pc.Add("@txt_old", OleDbType.VarChar);
  p.SourceVersion = DataRowVersion.Original;
  p = pc.Add("@dt_old", OleDbType.DBDate);
  p.SourceVersion = DataRowVersion.Original;
  p = pc.Add("@num_old", OleDbType.Integer);
  p.SourceVersion = DataRowVersion.Original;
  cmd.CommandText = "UPDATE tbl1 SET id = @id_new, txt = @txt_new, dt = @dt_new, num = @num_new"
           " WHERE id = @id_old AND txt = @txt_old AND dt = @dt_old AND num = @num_old";
  da.UpdateCommand = cmd;
  // delete
  da.DeleteCommand = new OleDbCommand();
  pc = da.DeleteCommand.Parameters;
  pc.Add("@id", OleDbType.Integer);
  p.SourceVersion = DataRowVersion.Original;
  pc.Add("@txt", OleDbType.VarChar);
  p.SourceVersion = DataRowVersion.Original;
  pc.Add("@dt", OleDbType.DBDate);
  p.SourceVersion = DataRowVersion.Original;
  pc.Add("@num", OleDbType.Integer);
  p.SourceVersion = DataRowVersion.Original;
  cmd.CommandText = "DELETE FROM tbl1 WHERE id = @id AND txt = @txt AND dt = @dt AND num = @num";
  da.DeleteCommand = cmd;
}

private void bindingNavigatorSaveItem_Click(object sender, EventArgs e)
{
  daUpdate();
  da.Update(ds.Tables[0]);
}
Я не уверен в правильности присвоения текущих значений параметрам. С базами данных я работаю впервые. Хотел бы спросить, как проверить правильность SQL запросов и правильность присвоения значений параметрам в отладчике. Я ставил точку останова после cmd.CommanText, но так и не смог убедиться в правильности создания коменд Insert, Update и Delete. При Insert (вставка новой строки) сообщений об ошибках нет, а при изменении строки появляется ошибка "Отсутствует значение для одного или нескольких требуемых параметров".
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #19 : 19-04-2013 19:31 » 

tumanovalex, я тоже не уверен: всё зависит либо от порядка, либо от имён, которые должны совпадать с именами колонок, и типы хорошо бы проверить. Раз отсутствуют значения, значит параметры неправильные.

И что значит "не смог убедиться"? При останове программы отладчик позволяет посмотреть любую переменную и её внутренности. В dataadapter всё видно. Значит не смотрел, тогда непонятно, как "пробовал убеждаться". Если не знаешь, куда посмотреть, так и спрашивай - никто ж не догадается. Ты вообще не рассказываешь, как что-то делаешь, как рассуждаешь, почему пишешь так, а не иначе - в результате, даже и сказать нечего. Наверно в чём-то заблуждаешься, но никто не может узнать, в чём именно.

Но я опять вижу бессмысленный код. Зачем ты пишешь строчки, которые не понимаешь? Откуда ты взял p.SourceVersion? Даже если где-то написано, не надо copy-paste делать. А если и делать, то каждую строчку проверить - зачем она нужна, чтобы знать.

Условия WHERE избыточны: достаточно проверять лишь первичный ключ таблицы. Более того, UPDATE даже работать не будет, поскольку записей с новыми значениями прото нет, и старая запись не будет найдена.

Проверять запросы хорошо в СУБД. Если у тебя база Access, то в Access и проверять. Т.е. сначала отладить запрос там, потом переносить его в код программы. У меня Access нету, поэтому как там что-то делать, я тебе не скажу: я его уже 5 лет в глаза не видел.
« Последнее редактирование: 19-04-2013 19:32 от Dimka » Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
tumanovalex
Помогающий

ru
Offline Offline

« Ответ #20 : 20-04-2013 04:52 » 

Спасибо за ответ. Попробую ответить по порядку:
1. Дурацкий код - это код из книг по ADO.NET (Seppa.ADO.NET.2.0 и S.Malik_Pro_ADO_NET20_2006). В основном там о SQL Server, но мне удобнее работать с Access. Для Access в книгах я ничего толкового не нашел, только про строку подключения.
2. Я действительно не знаю, куда смотреть и как правильно отлаживать работу с базой данных.
3. Я плохо понимаю, откуда брать значения, например в моем случае id и @id, как проверять старые и новые значения при update, откуда брать новые значения при insert и как удалять при delete.
Если подитожить все, что написано, то фактически я умею только создавать базу данных в Access, связывать там таблицы и вводить данные. Как только я пытаюсь работать в базой данных в C# с помощью ADO.NET - возникают проблемы. Видимо это потому, что я плохо себе представляю структуру команд и объектов в ADO.NET.
Фактически я методом тыка пытаюсь перенести код из книг и получается все неправильно. Если Вы дадите краткую пошаговую инструкцию освоения ADO.NET для Access, я был бы очень Вам признателен. А то я времени трачу очень много, а толку никакого - понимания не прибавляется.
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #21 : 20-04-2013 06:58 » 

tumanovalex, ну это почти что предложение написать мне брошюру об ADO.NET. У меня на это нет ни времени, ни желания. Структура объектов и методов не зависит от СУБД и подробно описана в MSDN - с примерами.

2) Куда смотреть. Раз умеешь останавливать программу, то про отладчик долго объяснять не буду. Вообще, в меню Debug содержится всё, что отладчик умеет. Простейший способ посмотреть: в остановленной программе навести мышь на переменную, и во всплывающем окне всё покажется. Активно забираться внутрь объектов через разворачивающиеся пункты. Ещё есть окна watch, в которых можно задать вычисляемое выражение, и там будет показываться его текущее значение в месте останова.

3) Я плохо понял, что значит "брать значения". Какие значения и зачем? Если для вызова dataadapter.update, то никаких значений брать не надо, надо лишь правильно настроить команды под структуру таблицы. UPDATE ничего не проверяет в базе, оно просто присваивает новые значения для всех найденных по условию записей. Если же речь про работу dataadapter.update, то у каждой datarow есть состояние: запись не менялась, менялась, добавлена новая, удалена - на этом основании dataadapter выбирает, какой командой обработать запись или ничего с ней не делать. Состояние меняется автоматически при операциях с записью или со значением её полей. На самом деле там ещё сложнее, там есть копия исходной строки - для обработки транзакций и возможности rollback, но это пока к делу не относится.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
tumanovalex
Помогающий

ru
Offline Offline

« Ответ #22 : 20-04-2013 08:43 » 

Самое для меня непонятное - как нужно задавать правильно параметры команд и как DataAdapter определяет нужные строки для добавления, удаления, обновления. Как правльно это делать? Я посмотрел примеры на MSDN, попробовал сделать что-то подобное:
Код:
private void daUpdate()
{
   string strIns = "INSERT INTO tbl1(id, txt, dt, num) VALUES(?, ?, ?, ?)";
  // insert
  OleDbCommand insertCmd = new OleDbCommand(strIns, con);
  da.InsertCommand = insertCmd;
  insertCmd.Parameters.Add("@id", OleDbType.Integer);
  insertCmd.Parameters.Add("@txt", OleDbType.VarChar);
  insertCmd.Parameters.Add("@dt", OleDbType.DBDate);
  insertCmd.Parameters.Add("@num", OleDbType.Integer);
  // update
  string strUpd = "UPDATE tbl1 SET id = ?, txt = ?, dt = ?, num = ?";
  OleDbCommand updateCmd = new OleDbCommand(strUpd, con);
  da.UpdateCommand = updateCmd;
  updateCmd.Parameters.Add("@id", OleDbType.Integer);
  updateCmd.Parameters.Add("@txt", OleDbType.VarChar);
  updateCmd.Parameters.Add("@dt", OleDbType.DBDate);
  updateCmd.Parameters.Add("@num", OleDbType.Integer);
  // delete
  string strDel = "DELETE FROM tbl1 WHERE id = ? AND txt = ? AND dt = ? AND num = ?";
  OleDbCommand deleteCmd = new OleDbCommand(strDel, con);
  da.DeleteCommand = deleteCmd;
  deleteCmd.Parameters.Add("@id", OleDbType.Integer);
  deleteCmd.Parameters.Add("@txt", OleDbType.VarChar);
  deleteCmd.Parameters.Add("@dt", OleDbType.DBDate);
  deleteCmd.Parameters.Add("@num", OleDbType.Integer);
}

private void bindingNavigatorSaveItem_Click(object sender, EventArgs e)
{
  da.Update(ds.Tables[0]);
}
Результат тот же - в базу ничего не вносится.
Записан
tumanovalex
Помогающий

ru
Offline Offline

« Ответ #23 : 20-04-2013 12:44 » 

Наконец-то получилось вставить данные в базу:
Код:
private void bindingNavigatorSaveItem_Click(object sender, EventArgs e
{
  OleDbParameter p;
  // insert
  string strIns = "INSERT INTO tbl1(id, txt) VALUES (?, ?)";
  OleDbCommand insertCmd = new OleDbCommand(strIns, con);
  da.InsertCommand = insertCmd;
  p = new OleDbParameter("@id", OleDbType.Integer);
  p.SourceColumn = "id";
  p.SourceVersion = DataRowVersion.Original;
  insertCmd.Parameters.Add(p);
  p = new OleDbParameter("@txt", OleDbType.VarChar);
  p.SourceColumn = "txt";
  p.SourceVersion = DataRowVersion.Original;
  insertCmd.Parameters.Add(p);
 // update
  string strUpd = "UPDATE tbl1 SET id = ?, txt = ?";
   //string strUpd = "UPDATE tbl1 SET txt = ?";
  OleDbCommand updateCmd = new OleDbCommand(strUpd, con);
  da.UpdateCommand = updateCmd;
  p = new OleDbParameter("@id", OleDbType.Integer);
  p.SourceColumn = "id";
  p.SourceVersion = DataRowVersion.Original;
  updateCmd.Parameters.Add(p);
  p = new OleDbParameter("@txt", OleDbType.VarChar);
  p.SourceColumn = "txt";
  p.SourceVersion = DataRowVersion.Original;
  updateCmd.Parameters.Add(p);
  // delete
  string strDel = "DELETE FROM tbl1 WHERE id = ? AND txt = ?";
  OleDbCommand deleteCmd = new OleDbCommand(strDel, con);
  da.DeleteCommand = deleteCmd;
  p = new OleDbParameter("@id", OleDbType.Integer);
  p.SourceColumn = "id";
  p.SourceVersion = DataRowVersion.Original;
  deleteCmd.Parameters.Add(p);
  p = new OleDbParameter("@txt", OleDbType.VarChar);
  p.SourceColumn = "txt";
  p.SourceVersion = DataRowVersion.Original;
  deleteCmd.Parameters.Add(p);
  da.Update(ds.Tables[0]);
}
Но не получается update. При изменении поля txt и попытке записи получаю "Невозможно обновить поле 'id'; не обновляемое поле". Буду разбираться дальше. Спасибо Вам большое за советы и помощь.
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #24 : 20-04-2013 13:18 » new

tumanovalex, правильно: autoincrement поле первичного ключа не может изменяться. Более того, я не советую даже выводить его на экран. и в UPDATE у тебя нет условия выбора WHERE - команда применяется ко всем записям в таблице, что неправильно.

Я уже не первый раз это упоминаю, но складывается впечатление, что для тебя "первичный ключ" (primary key) - какой-то пустой звук. Если это так, стоит отложить .NET и разобраться с реляционными базами данных вообще.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
tumanovalex
Помогающий

ru
Offline Offline

« Ответ #25 : 20-04-2013 16:47 » 

Да нет, про первичных ключ я знаю. И понимаю, что его нельзя обновлять. Получилось так:
Код: (C#)
string strUpd = "UPDATE tbl1 SET txt = ? WHERE id = ?";
OleDbCommand updateCmd = new OleDbCommand(strUpd, con);
da.UpdateCommand = updateCmd;
p = new OleDbParameter("@txt", OleDbType.VarChar);
p.SourceColumn = "txt";
p.SourceVersion = DataRowVersion.Current;
updateCmd.Parameters.Add(p);
p = new OleDbParameter("@id", OleDbType.Integer);
p.SourceColumn = "id";
p.SourceVersion = DataRowVersion.Original;
updateCmd.Parameters.Add(p);
А пользователю я не собираюсь первичные ключи показывать. Это так, для отладки.
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines