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


Автор: Amburgen 4.12.2006, 20:37
Помогите пожалуйста вот по какому вопросу.
Есть две таблицы : 
1) Таблица людей ([Person_ID], [Person_Name])
2) Таблица их друзей ([Friend_ID], [Friend_Name], [Person_name] (или [Person_ID] ))

Содержимое таблицы Person отображается в одном компоненте (на Windows-ворме) . Во втором компоненте должны отобразится все друзья выбраного Person-а в первом компоненте. При изменении выбраного Person-а в 1-м компоненте, изменяется содержимое во втором компоненте.

Я создаю типизированый дата сет dsRelation, в который заливаю 2 таблицы. Прописываю связь между полями 
Код

dataset.Relations.Add("Person_Friend", dataset.Tables["Person"].Columns["Person_Name"], dataset.Tables["Friend"].Columns["Person_Name"]);
dataset.Relations[0].Nested = true;

и связываю таблицу с компонентами на форме
Код

        dataset.LoadData();
        dsRelation dataset = new dsRelation();
        BindingSource BindPerson = new BindingSource();
        BindingSource BindFriend = new BindingSource();

             BindPerson.DataSource = dataset.Person;
            BindFriend.DataSource = dataset.Friend;

            gvPerson.DataSource = BindPerson;
            gvFriend.DataSource = BindFriend;
            
            cbPerson.DataSource = BindPerson;
            cbPerson.DisplayMember = "Person_Name";
            lbFriend.DataSource = BindFriend;
            lbFriend.DisplayMember = "Friend_Name";


 Но мне отображает все подряд (всех Friend-ов из таблицы).
Подскажите что я делаю не так.

Автор: mr.DUDA 4.12.2006, 20:55
Видимо, CurrencyManager "не подхватывает" binding у парент-таблицы. Либо не задано ключевое поле у табл. Persons, либо надо заполнить cbPersons.ValueMember (это комбобокс, если я правильно понял).

Автор: Amburgen 4.12.2006, 21:11
mr.DUDA, 
Напишите пожалуйста по-подробнее про CurrencyManager, и про то, как он должен "подхватівать" binding, а также про ValueMember  и чем его надо заполнить (я только начинаю работать с базами).

Автор: thomas 4.12.2006, 22:22
Amburgen, 
Привет.
Если у тебя на форме есть комбобокс, который надо заполнить персонами и тебе надо отобразить всех его друзей в листбоксе или в датагридвью, то я бы сделал так:

заполняем комбо
Код

sql= "SELECT namePerson FROM tablePerson"

Command.CommandText=sql
DataAdapter=New DataAdapter(Command)
DataAdapter.Fill(DataSet, "person")

for each DataRow dr in DataSeT.Tables("person").Rows
ComboBox.Items.Add(dr(0))


В твоем комбо теперь все персоны.
Теперь делаем выбору из другой таблицы всех друзей выбранной персоны 
и прописываем это в событие изменения выделенного элемента в комбо

Код

sql = "SELECT * FROM tableFriend WHERE personName= " + ComboBox.SelectedItem.ToString()

Command.CommandText=sql
DataAdapter=New DataAdapter(Command)
DataAdapter.Fill(DataSet, "friend")

DataGridView.DataSource = DataSet
DataGridView.DataMember= "friend"


или 
построчно заполняешь листбокс.

Автор: mr.DUDA 4.12.2006, 23:07
Amburgen, CurrencyManager управляет так называемой "позицией" в источнике данных. Упрощённо механизм binding действует так: мы привязываем контролы к свойствам источника данных, например при изменении свойства объекта MyObject, автоматически изменяется Text в текстбоксе, или Color, и так далее. Когда под источником данных подразумевается один объект, то за сценой работает класс PropertyManager, отслеживая изменения в контроле и наоборот, в свойстве объекта, передавая значения в ту или иную сторону. Другое дело, когда источник данных представляет множество объектов, проще говоря - массив или список (как DataTable, который состоит из списка DataRow). Здесь срабатывает CurrencyManager, в обязанности которого входит управление позицией в массиве/списке. Как именно выбирается nnnManager - зависит от природы источника данных; этим управляет WinForms. Так вот, CurrencyManager расчитан на некоторые правила, по которым строится источник данных, для того чтобы корректно определять позицию в нём: для DataTable таким правилом является наличие первичного ключа (primary key). В дизайнере датасета можно настроить первичный ключ, используя контекстное меню колонки таблицы.

По поводу ValueMember, для компонента ComboBox именно ValueMember задаёт (определяет) свойство источника данных, откуда CurrencyManager получает позицию. В общем случае, любая таблица датасета должна содержать ID (идентификатор). Имя поля, содержащего идентификатор записи таблицы, нужно поместить в ValueMember (точно так же как в DisplayMember помещается имя поля таблицы, содержащего строки для вывода в комбобоксе). То есть, если не определить ValueMember, комбобокс будет связан с таблицей, но записи будут отображаться без связи с их ID - выбор какой-то конкретной записи не приведёт ни к чему, т.к. binding завязан именно на ID (первичный ключ).

thomas, можно и вручную всё делать: навесить обработчик на изменение текущей записи в комбобоксе, и динамически управлять соответствующими контролами. Но в случае более-менее сложной формы (множество контролов со связями) намного выгоднее использовать стандартные механизмы управления данными, чем изобретать свои. А изобретать придётся (binding скрывает от разработчика немалое количество "ненужной", грязной работы).

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