| 
			| 
					
						| tumanovalex 
								Помогающий    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"];
 }
Хотелось бы с этим разобраться. |  
						| 
								| 
 |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| Dimka 
								ДеятельКоманда клуба    Offline 
								Пол:    | 
								|  | « Ответ #1 : 11-04-2013 17:59 »  |  | 
 
 tumanovalex, а как ты себе представляешь результат? |  
						| 
								|  |  
								|  |  Записан | 
 
 Программировать - значит понимать (К. Нюгард)Невывернутое лучше, чем вправленное (М. Аврелий)
 Многие готовы скорее умереть, чем подумать (Б. Рассел)
 |  |  | 
	| 
			| 
					
						| tumanovalex 
								Помогающий    Offline | 
								|  | « Ответ #2 : 12-04-2013 11:56 »  |  | 
 
 Представляю его так: при установке выделения на строку таблицы Contacts при вводе нового телефона в поле idContacts таблицы Phone появлялось бы значение из поля idContacts выбранной строки контакта. |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| Dimka 
								ДеятельКоманда клуба    Offline 
								Пол:    | 
								|  | « Ответ #3 : 12-04-2013 16:42 »  |  | 
 
 tumanovalex, и где код визуальной части? где связь источников данных с элементами формы? |  
						| 
								|  |  
								|  |  Записан | 
 
 Программировать - значит понимать (К. Нюгард)Невывернутое лучше, чем вправленное (М. Аврелий)
 Многие готовы скорее умереть, чем подумать (Б. Рассел)
 |  |  | 
	| 
			| 
					
						| tumanovalex 
								Помогающий    Offline | 
								|  | « Ответ #4 : 12-04-2013 18:17 »  |  | 
 
 Как я понял, код визуальной части и жесткая связь источников данных с элементами формы нужна для типизированного DataSet. А я заполняю контролы с помощью нетипизированного DataSet и DataAdapter. |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| Dimka 
								ДеятельКоманда клуба    Offline 
								Пол:    | 
								|  | « Ответ #5 : 12-04-2013 21:20 »  |  | 
 
 tumanovalex, проблема в том, что ты говоришь о каких-то вещах, которые считаешь очевидными для всех. Это не так. Хотя бы мог усомниться, потому что ты сам точно не знаешь, что ты говоришь, и насколько правильно ты говоришь и понимаешь. А телепатов тут не водится.
 Поэтому или ты рассказываешь подробно и обстоятельно, или я не знаю, чем тебе помогать. Тот код, что ты привёл, лишь создаёт структуру данных. Из этого никаких проблем не следует.
 |  
						| 
								|  |  
								|  |  Записан | 
 
 Программировать - значит понимать (К. Нюгард)Невывернутое лучше, чем вправленное (М. Аврелий)
 Многие готовы скорее умереть, чем подумать (Б. Рассел)
 |  |  | 
	| 
			| 
					
						| tumanovalex 
								Помогающий    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 нового номера телефона при щелчке на знаке "+". Прикрепляю новый проект, в котором введены номера телефонов и из которого, наверное, будет все ясно.
 |  
						| 
								| 
 |  
								| « Последнее редактирование: 13-04-2013 06:36 от tumanovalex » |  Записан | 
 |  |  | 
	| 
			| 
					
						| Dimka 
								ДеятельКоманда клуба    Offline 
								Пол:    | 
								|  | « Ответ #7 : 13-04-2013 10:41 »  |  | 
 
 tumanovalex, ну во-первых, твои grid ничего не знают о наличии связи. И никаким шаманством оно само по себе не догадается. Хотя бы по той причине, что количество и характер связей в dataset могут быть самыми разнообразными. Для правильного binding нужно помимо datasource указать datamember - на что ориентироваться grid'у. Для master это будет имя datatable, для detail это будет имя datarelation.
 Во-вторых, datarelation настраивает grid на работу не с таблицей, а с отфильтрованным представлением таблицы, откуда следует, что операции добавления новых элементов в таблицу становятся менее тривиальными. Как минимум, нужно позаботиться о значениях по-умолчанию для связующего ключа, да и autoincrement поля тоже перестают работать.
 |  
						| 
								|  |  
								|  |  Записан | 
 
 Программировать - значит понимать (К. Нюгард)Невывернутое лучше, чем вправленное (М. Аврелий)
 Многие готовы скорее умереть, чем подумать (Б. Рассел)
 |  |  | 
	| 
			| 
					
						| tumanovalex 
								Помогающий    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;
 }
 Не уверен, что в коде нет лишних элементов. Посмотрите, пожалуйста, правильно ли я понял Ваши разъяснения и нет ли чего в коде лишнего. Проект прикрепляю |  
						| 
								| 
 |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| Dimka 
								ДеятельКоманда клуба    Offline 
								Пол:    | 
								|  | « Ответ #9 : 15-04-2013 08:51 »  |  | 
 
 tumanovalex, ну в начале там зачем-то настраивается запрос, потом затирается новым, потом опять восстанавливается. А binding и так есть в grid, т.е. свойства datamember и datasource можно присваивать прямо в grid без промежуточных объектов. |  
						| 
								|  |  
								|  |  Записан | 
 
 Программировать - значит понимать (К. Нюгард)Невывернутое лучше, чем вправленное (М. Аврелий)
 Многие готовы скорее умереть, чем подумать (Б. Рассел)
 |  |  | 
	| 
			| 
					
						| tumanovalex 
								Помогающий    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 
								ДеятельКоманда клуба    Offline 
								Пол:    | 
								|  | « Ответ #11 : 16-04-2013 08:21 »  |  | 
 
 tumanovalex, не увидел разницы с предыдущим, кроме комментариев. Я и не говорил, что схемы не грузить. Я только не понимаю, почему это не делать сразу с fill, а надо по 2 раза перенастраивать dataadapter. |  
						| 
								|  |  
								|  |  Записан | 
 
 Программировать - значит понимать (К. Нюгард)Невывернутое лучше, чем вправленное (М. Аврелий)
 Многие готовы скорее умереть, чем подумать (Б. Рассел)
 |  |  | 
	| 
			| 
					
						| tumanovalex 
								Помогающий    Offline | 
								|  | « Ответ #12 : 16-04-2013 14:37 »  |  | 
 
 Спасибо за ответ. Попробовал сделать так, как Вы советовали (разместил загрузку схемы рядом с fill), все заработало нормально. Теперь возникла задача внести в базу данных изменения, которые я сделал в формах. Подскажите, пожалуйста, как это можно сделать. По имеющейся у меня книге Малик Сахил "Microsoft ADO.NET 2.0 для профессионалов" я разобраться не смог. |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| Dimka 
								ДеятельКоманда клуба    Offline 
								Пол:    | 
								|  | « Ответ #13 : 16-04-2013 20:11 »  |  | 
 
 tumanovalex, dataadapter имеет все 4 команды работы с данными. Поскольку определён лишь select, то и программа работает лишь на чтение из базы. Если доопределить остальные команды insert, update, delete, то будет полная синхронизация с базой. Однако нужно вручную вызывать dataadapter.update, который выгружает данные из dataset в базу. Вызывать его можно, например, по событию изменения в grid или в datatable. |  
						| 
								|  |  
								|  |  Записан | 
 
 Программировать - значит понимать (К. Нюгард)Невывернутое лучше, чем вправленное (М. Аврелий)
 Многие готовы скорее умереть, чем подумать (Б. Рассел)
 |  |  | 
	| 
			| 
					
						| tumanovalex 
								Помогающий    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 не вносятся. Подскажите, пожалуйста, в чем ошибка. |  
						| 
								| 
 |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| Dimka 
								ДеятельКоманда клуба    Offline 
								Пол:    | 
								|  | « Ответ #15 : 19-04-2013 08:09 »  |  | 
 
 tumanovalex, во-первых, меня не радует каждый раз выгружать проект и ковыряться в коде. Это работа разработчика - искать ошибки. Получается, что я за тебя выполняю твою работу по отладке.
 Т.е. позиция: "У меня тут не работает проект - разбирайтесь в моём творении" - неправильная позиция. Пользуйся отладчиком, изучай язык, среду и Framework. Причём ни на форуме, ни книжки тебя не научат, где и что в студии смотреть - это всецело твой личный expirience, наработанный самостоятельно.
 
 Во-вторых по содержанию. Ты не понимаешь, что делает тот код, который ты пишешь. В твоём решении все команды dataadapter содержат DELETE - т.е. самую последнюю присвоенную. По той причине, что ты вместо создания объектов command всё пишешь в единственный объект. Поскольку классы - ссылочные типы, копируются только ссылки на команду, но не сами объекты. Программист должен смотреть на объекты, а не только на переменные в коде - писать осознанно и вдумчиво.
 |  
						| 
								|  |  
								|  |  Записан | 
 
 Программировать - значит понимать (К. Нюгард)Невывернутое лучше, чем вправленное (М. Аврелий)
 Многие готовы скорее умереть, чем подумать (Б. Рассел)
 |  |  | 
	| 
			| 
					
						| tumanovalex 
								Помогающий    Offline | 
								|  | « Ответ #16 : 19-04-2013 14:20 »  |  | 
 
 Справедливые замечания. Но без помощи на форумах мне вряд ли удастся разобраться. Нет коллектива программистов, который бы мог помочь, работа с программированием не связана, это хобби. Буду пытаться разбираться дальше, но, видимо, уже без Вашей помощи. Спасибо за советы.   |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| Dimka 
								ДеятельКоманда клуба    Offline 
								Пол:    | 
								|  | « Ответ #17 : 19-04-2013 17:11 »  |  | 
 
 tumanovalex, советы разработчиков как правило позитивны: как что-то сделать, какой подход/архитектуру/технологию/шаблон проектирования применить; бывают пояснения о том, как что-то работает или устроено.
 Но отладка, ловля ошибок - это повседневная работа, которая занимает 50-100% рабочего времени. Потому что что-то плохо документировано, или разработчик не знает, как чем-то пользоваться, и пишет методом проб и ошибок. Поскольку это почти у всех так, приходить к другим с "найди мне, где у меня ошибка" - это именно перекладывание своей работы на другого.
 
 "Начинающий" - тут не оправдание. Любой начинающий проходит такой этап, на котором его главное приобретение: научиться искать ошибки и читать документацию самостоятельно.
 
 Да, это некомфортное состояние: лбом об стену. Не работает, и не знаешь, что делать, и не знаешь, когда это закончится, и непродуктивно, и скучно. Но такая вот работа, особенно на неизведанных территориях с незнакомыми технологиями. Но это не повод перекладывать свою работу на других за просто так. Это повод продумать план исследования проблемы и наметить гипотезы возникновения ошибки, продумать способы проверки, протоколирования работы машины, проанализировать полученные результаты проверок, отобрать перспективные гипотезы, определить нужные изменения. И так шаг за шагом, проблема за проблемой.
 |  
						| 
								|  |  
								|  |  Записан | 
 
 Программировать - значит понимать (К. Нюгард)Невывернутое лучше, чем вправленное (М. Аврелий)
 Многие готовы скорее умереть, чем подумать (Б. Рассел)
 |  |  | 
	| 
			| 
					
						| tumanovalex 
								Помогающий    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 
								ДеятельКоманда клуба    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 
								Помогающий    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 
								ДеятельКоманда клуба    Offline 
								Пол:    | 
								|  | « Ответ #21 : 20-04-2013 06:58 »  |  | 
 
 tumanovalex, ну это почти что предложение написать мне брошюру об ADO.NET. У меня на это нет ни времени, ни желания. Структура объектов и методов не зависит от СУБД и подробно описана в MSDN - с примерами.
 2) Куда смотреть. Раз умеешь останавливать программу, то про отладчик долго объяснять не буду. Вообще, в меню Debug содержится всё, что отладчик умеет. Простейший способ посмотреть: в остановленной программе навести мышь на переменную, и во всплывающем окне всё покажется. Активно забираться внутрь объектов через разворачивающиеся пункты. Ещё есть окна watch, в которых можно задать вычисляемое выражение, и там будет показываться его текущее значение в месте останова.
 
 3) Я плохо понял, что значит "брать значения". Какие значения и зачем? Если для вызова dataadapter.update, то никаких значений брать не надо, надо лишь правильно настроить команды под структуру таблицы. UPDATE ничего не проверяет в базе, оно просто присваивает новые значения для всех найденных по условию записей. Если же речь про работу dataadapter.update, то у каждой datarow есть состояние: запись не менялась, менялась, добавлена новая, удалена - на этом основании dataadapter выбирает, какой командой обработать запись или ничего с ней не делать. Состояние меняется автоматически при операциях с записью или со значением её полей. На самом деле там ещё сложнее, там есть копия исходной строки - для обработки транзакций и возможности rollback, но это пока к делу не относится.
 |  
						| 
								|  |  
								|  |  Записан | 
 
 Программировать - значит понимать (К. Нюгард)Невывернутое лучше, чем вправленное (М. Аврелий)
 Многие готовы скорее умереть, чем подумать (Б. Рассел)
 |  |  | 
	| 
			| 
					
						| tumanovalex 
								Помогающий    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 
								Помогающий    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 
								ДеятельКоманда клуба    Offline 
								Пол:    | 
								|  | « Ответ #24 : 20-04-2013 13:18 »  |  | 
 
 tumanovalex, правильно: autoincrement поле первичного ключа не может изменяться. Более того, я не советую даже выводить его на экран. и в UPDATE у тебя нет условия выбора WHERE - команда применяется ко всем записям в таблице, что неправильно.
 Я уже не первый раз это упоминаю, но складывается впечатление, что для тебя "первичный ключ" (primary key) - какой-то пустой звук. Если это так, стоит отложить .NET и разобраться с реляционными базами данных вообще.
 |  
						| 
								|  |  
								|  |  Записан | 
 
 Программировать - значит понимать (К. Нюгард)Невывернутое лучше, чем вправленное (М. Аврелий)
 Многие готовы скорее умереть, чем подумать (Б. Рассел)
 |  |  | 
	| 
			| 
					
						| tumanovalex 
								Помогающий    Offline | 
								|  | « Ответ #25 : 20-04-2013 16:47 »  |  | 
 
 Да нет, про первичных ключ я знаю. И понимаю, что его нельзя обновлять. Получилось так: 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);
 А пользователю я не собираюсь первичные ключи показывать. Это так, для отладки. |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	|  |