Home All Groups Group Topic Archive Search About

binding tables in many-to-many relationships

Author
23 Oct 2006 5:05 PM
Ryan
Hello all.  I'm having some (mis?)adventures in databinding a winforms app
and need some guidance.

My data model has 4 tables, let us call them Leases, Terms, LeaseTerms, and
LeaseTermTypes.  The idea is that you can setup several definitions of Terms,
several definitions of Leases, and the two of them get related together in
LeaseTerms (standard intermediary tabling to avoid many-to-many).  On
LeaseTerms is a foreign key to LeaseTermType (for clarity the create script
for these tables is at the bottom of the post)

On my WinForm app I have 2 comboboxes - one for LeaseTermType and the other
for Terms.  What I want to do is for whatever LeaseTermType that has been
selected, I want to populate the 2nd combo box with all associated
Lease.LeaseTermName values (going through the LeaseTerms table).  I'm
currently trying to do this using BindSoucres that bind to the relationships
defined in my dataset.

Now, this all currently works fine and dandy except that from the LeaseTerms
perspective, there's a 1-to-1 relationship from LeaseTerms to Leases.  So
what's happening is that my 2nd combobox is only displaying 1 record rather
than a record for each of the records contained in the filtered LeaseTerms
table.

Is there any way to get all the Leases rather than just the 1 using the
built-in UI binding?  I could write code to do all this, but ideally I'd like
to spend 15 seconds pointing and clicking rather than a few minutes hacking
code.

Any help and or guidance is appreciated.

Here's the script for our example DB.

/****** Object:  Table [dbo].[Leases]    Script Date: 10/23/2006 10:59:14
******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Leases](
    [LeaseID] [uniqueidentifier] NOT NULL,
    [LeaseName] [varchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
PRIMARY KEY CLUSTERED
(
    [LeaseID] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

GO
SET ANSI_PADDING OFF
GO
/****** Object:  Table [dbo].[LeaseTerms]    Script Date: 10/23/2006
10:59:15 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[LeaseTerms](
    [LeaseTermID] [uniqueidentifier] NOT NULL,
    [LeaseID] [uniqueidentifier] NULL,
    [TermID] [uniqueidentifier] NULL,
    [LeaseTermTypeID] [uniqueidentifier] NULL,
PRIMARY KEY CLUSTERED
(
    [LeaseTermID] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

GO
/****** Object:  Table [dbo].[LeaseTermTypes]    Script Date: 10/23/2006
10:59:15 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[LeaseTermTypes](
    [LeaseTermTypeID] [uniqueidentifier] NOT NULL,
    [LeaseTermTypeName] [varchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
PRIMARY KEY CLUSTERED
(
    [LeaseTermTypeID] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

GO
SET ANSI_PADDING OFF
GO
/****** Object:  Table [dbo].[Terms]    Script Date: 10/23/2006 10:59:15
******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Terms](
    [TermID] [uniqueidentifier] NOT NULL,
    [TermName] [varchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
PRIMARY KEY CLUSTERED
(
    [TermID] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

GO
SET ANSI_PADDING OFF
GO
USE [DeleteMe]
GO
ALTER TABLE [dbo].[LeaseTerms]  WITH CHECK ADD  CONSTRAINT
[FK_LeaseTerms_Leases] FOREIGN KEY([LeaseID])
REFERENCES [dbo].[Leases] ([LeaseID])
GO
ALTER TABLE [dbo].[LeaseTerms]  WITH CHECK ADD  CONSTRAINT
[FK_LeaseTerms_LeaseTermTypes] FOREIGN KEY([LeaseTermTypeID])
REFERENCES [dbo].[LeaseTermTypes] ([LeaseTermTypeID])
GO
ALTER TABLE [dbo].[LeaseTerms]  WITH CHECK ADD  CONSTRAINT
[FK_LeaseTerms_Terms] FOREIGN KEY([TermID])
REFERENCES [dbo].[Terms] ([TermID])

Author
24 Oct 2006 9:43 AM
WenYuan Wang
Hi,

First of all, I¡¯d like to confirm my understanding of your issue.
According to your description, I understand that you want to know how to
get the related rows from many-to-many related tables.
If I misunderstood anything here, please don¡¯t hesitate to correct me. 

Databinding is a very useful tool when you have two tables which are
related, but it¡¯s not powerful enough to relate three tables.

According to your scenario, you can use DataRelation. You can create one
DataSet which has three DataTables ( Leases, LeaseTerms and LeaseTermTypes).
Eeach DataTable has a relationship to another DataTable. Using
DataTable.getChildRows(), you can get related rows.
When ComboBox(LeaseTermType) has been selected, the following code snippet
can be used to populate the 2nd combo box with all associated leases.

DataRow selectRow = ((DataRowView)this.comboBox1.SelectedItem).Row;
DataRow[] LeaseTermsDRs = selectRow.GetChildRows("dr2");
//"dr2" means the Relationship Betwen LeaseTermTypes and LeaseTerms
DataTable leasedt=ds.Tables["Leases"].Clone();
foreach (DataRow dr in LeaseTermsDRs)
{
  leasedt.Rows.Add(dr.GetParentRow("dr1").ItemArray);
  //"dr1" means the Relationship Betwen LeaseTermTypes and Leases
}
this.comboBox2.DataSource = leasedt;
this.comboBox2.DisplayMember = "LeaseName"; 

I have done some sample code according to your scenario, you can try the
following code snippet if it is works on your machine.

private void init()
{
  System.Data.SqlClient.SqlConnection scn=new
System.Data.SqlClient.SqlConnection("¡­¡­");
  System.Data.SqlClient.SqlDataAdapter sda=new
System.Data.SqlClient.SqlDataAdapter();
  System.Data.SqlClient.SqlCommand scd=new
System.Data.SqlClient.SqlCommand();
  scd.Connection=scn;
  sda.SelectCommand=scd;
  scn.Open();
  scd.CommandText="select * from Leases";
  sda.Fill(ds,"Leases");
  scn.Close();
  scn.Open();
  scd.CommandText="select * from LeaseTerms";
  sda.Fill(ds,"LeaseTerms");
  scn.Close();
  scn.Open();
  scd.CommandText="select * from LeaseTermTypes";
  sda.Fill(ds,"LeaseTermTypes");
  scn.Close();
  ds.Relations.Add("dr1", ds.Tables["Leases"].Columns["LeaseID"],
ds.Tables["LeaseTerms"].Columns["LeaseID"]);
  ds.Relations.Add("dr2",
ds.Tables["LeaseTermTypes"].Columns["LeaseTermTypeID"],ds.Tables["LeaseTerms
"].Columns["LeaseTermTypeID"]);
  this.comboBox1.DisplayMember = "LeaseTermTypeName";
  this.comboBox1.ValueMember = "LeaseTermTypeID";
  this.comboBox1.DataSource=ds.Tables["LeaseTermTypes"];
}

private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
  DataRow selectRow = ((DataRowView)this.comboBox1.SelectedItem).Row;
  DataRow[] LeaseTermsDRs = selectRow.GetChildRows("dr2");
  DataTable leasedt=ds.Tables["Leases"].Clone();
  foreach (DataRow dr in LeaseTermsDRs)
  {
    leasedt.Rows.Add(dr.GetParentRow("dr1").ItemArray);
  }
  this.comboBox2.DataSource = leasedt;
  this.comboBox2.DisplayMember = "LeaseName";
}

If anything is unclear, please don¡¯t hesitate to post in the newsgroup and
we will follow up.

Wen Yuan
Microsoft Online Community Support
===============================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
===============================
(This posting is provided "AS IS", with no warranties, and confers no
rights.)
Author
24 Oct 2006 10:52 AM
Otis Mukinfus
On Tue, 24 Oct 2006 09:43:38 GMT, v-wyw***@online.microsoft.com (WenYuan Wang)
wrote:

Show quote
>Hi,
>
>First of all, I¡¯d like to confirm my understanding of your issue.
>According to your description, I understand that you want to know how to
>get the related rows from many-to-many related tables.
>If I misunderstood anything here, please don¡¯t hesitate to correct me. 
>
>Databinding is a very useful tool when you have two tables which are
>related, but it¡¯s not powerful enough to relate three tables.
>
>According to your scenario, you can use DataRelation. You can create one
>DataSet which has three DataTables ( Leases, LeaseTerms and LeaseTermTypes).
>Eeach DataTable has a relationship to another DataTable. Using
>DataTable.getChildRows(), you can get related rows.
>When ComboBox(LeaseTermType) has been selected, the following code snippet
>can be used to populate the 2nd combo box with all associated leases.
>
>DataRow selectRow = ((DataRowView)this.comboBox1.SelectedItem).Row;
>DataRow[] LeaseTermsDRs = selectRow.GetChildRows("dr2");
>//"dr2" means the Relationship Betwen LeaseTermTypes and LeaseTerms
>DataTable leasedt=ds.Tables["Leases"].Clone();
>foreach (DataRow dr in LeaseTermsDRs)
>{
>  leasedt.Rows.Add(dr.GetParentRow("dr1").ItemArray);
>  //"dr1" means the Relationship Betwen LeaseTermTypes and Leases
>}
>this.comboBox2.DataSource = leasedt;
>this.comboBox2.DisplayMember = "LeaseName"; 
>
>I have done some sample code according to your scenario, you can try the
>following code snippet if it is works on your machine.
>
>private void init()
>{
>  System.Data.SqlClient.SqlConnection scn=new
>System.Data.SqlClient.SqlConnection("¡­¡­");
>  System.Data.SqlClient.SqlDataAdapter sda=new
>System.Data.SqlClient.SqlDataAdapter();
>  System.Data.SqlClient.SqlCommand scd=new
>System.Data.SqlClient.SqlCommand();
>  scd.Connection=scn;
>  sda.SelectCommand=scd;
>  scn.Open();
>  scd.CommandText="select * from Leases";
>  sda.Fill(ds,"Leases");
>  scn.Close();
>  scn.Open();
>  scd.CommandText="select * from LeaseTerms";
>  sda.Fill(ds,"LeaseTerms");
>  scn.Close();
>  scn.Open();
>  scd.CommandText="select * from LeaseTermTypes";
>  sda.Fill(ds,"LeaseTermTypes");
>  scn.Close();
>  ds.Relations.Add("dr1", ds.Tables["Leases"].Columns["LeaseID"],
>ds.Tables["LeaseTerms"].Columns["LeaseID"]);
>  ds.Relations.Add("dr2",
>ds.Tables["LeaseTermTypes"].Columns["LeaseTermTypeID"],ds.Tables["LeaseTerms
>"].Columns["LeaseTermTypeID"]);
>  this.comboBox1.DisplayMember = "LeaseTermTypeName";
>  this.comboBox1.ValueMember = "LeaseTermTypeID";
>  this.comboBox1.DataSource=ds.Tables["LeaseTermTypes"];
>}
>
>private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
>{
>  DataRow selectRow = ((DataRowView)this.comboBox1.SelectedItem).Row;
>  DataRow[] LeaseTermsDRs = selectRow.GetChildRows("dr2");
>  DataTable leasedt=ds.Tables["Leases"].Clone();
>  foreach (DataRow dr in LeaseTermsDRs)
>  {
>    leasedt.Rows.Add(dr.GetParentRow("dr1").ItemArray);
>  }
>  this.comboBox2.DataSource = leasedt;
>  this.comboBox2.DisplayMember = "LeaseName";
>}
>
>If anything is unclear, please don¡¯t hesitate to post in the newsgroup and
>we will follow up.
>
>Wen Yuan
>Microsoft Online Community Support
>===============================
>When responding to posts, please "Reply to Group" via your newsreader so
>that others may learn and benefit from your issue.
>===============================
>(This posting is provided "AS IS", with no warranties, and confers no
>rights.)
Wen Yuan,

Please check the language settings on your computer.  The text you are sending
occasionally contains some non-English characters ( as in **don¡¯t** ).

Good luck with your project,

Otis Mukinfus
http://www.arltex.com
http://www.tomchilders.com
Author
26 Oct 2006 12:14 PM
WenYuan Wang
Hi Otis
Thanks for your reply.
I should do correct my post.
======================================
Hi,
First of all, I'd like to confirm my understanding of your issue.
According to your description, I understand that you want to know how to
get the related rows from many-to-many related tables.
If I misunderstood anything here, please don't hesitate to correct me. 

Databinding is a very useful tool when you have two tables which are
related, but it's not powerful enough to relate three tables.

According to your scenario, you can use DataRelation. You can create one
DataSet which has three DataTables (Leases, LeaseTerms and LeaseTermTypes).
Eeach DataTable has a relationship to another DataTable. Using
DataTable.getChildRows(), you can get related rows.
When ComboBox(LeaseTermType) has been selected, the following code snippet
can be used to populate the 2nd combo box with all associated leases.

DataRow selectRow = ((DataRowView)this.comboBox1.SelectedItem).Row;
DataRow[] LeaseTermsDRs = selectRow.GetChildRows("dr2");
//"dr2" means the Relationship Betwen LeaseTermTypes and LeaseTerms
DataTable leasedt=ds.Tables["Leases"].Clone();
foreach (DataRow dr in LeaseTermsDRs)
{
  leasedt.Rows.Add(dr.GetParentRow("dr1").ItemArray);
  //"dr1" means the Relationship Betwen LeaseTermTypes and Leases
}
this.comboBox2.DataSource = leasedt;
this.comboBox2.DisplayMember = "LeaseName"; 

I have done some sample code according to your scenario, you can try the
following code snippet if it is works on your machine.

private void init()
{
  System.Data.SqlClient.SqlConnection scn=new
System.Data.SqlClient.SqlConnection("...");
  System.Data.SqlClient.SqlDataAdapter sda=new
  System.Data.SqlClient.SqlDataAdapter();
  System.Data.SqlClient.SqlCommand scd=new
  System.Data.SqlClient.SqlCommand();
  scd.Connection=scn;
  sda.SelectCommand=scd;
  scn.Open();
  scd.CommandText="select * from Leases";
  sda.Fill(ds,"Leases");
  scn.Close();
  scn.Open();
  scd.CommandText="select * from LeaseTerms";
  sda.Fill(ds,"LeaseTerms");
  scn.Close();
  scn.Open();
  scd.CommandText="select * from LeaseTermTypes";
  sda.Fill(ds,"LeaseTermTypes");
  scn.Close();
  ds.Relations.Add("dr1", ds.Tables["Leases"].Columns["LeaseID"],
  ds.Tables["LeaseTerms"].Columns["LeaseID"]);
  ds.Relations.Add("dr2",
ds.Tables["LeaseTermTypes"].Columns["LeaseTermTypeID"],ds.Tables["LeaseTerms
"].Columns["LeaseTermTypeID"]);
  this.comboBox1.DisplayMember = "LeaseTermTypeName";
  this.comboBox1.ValueMember = "LeaseTermTypeID";
  this.comboBox1.DataSource=ds.Tables["LeaseTermTypes"];
}

private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
  DataRow selectRow = ((DataRowView)this.comboBox1.SelectedItem).Row;
  DataRow[] LeaseTermsDRs = selectRow.GetChildRows("dr2");
  DataTable leasedt=ds.Tables["Leases"].Clone();
  foreach (DataRow dr in LeaseTermsDRs)
  {
    leasedt.Rows.Add(dr.GetParentRow("dr1").ItemArray);
  }
  this.comboBox2.DataSource = leasedt;
  this.comboBox2.DisplayMember = "LeaseName";
}
Author
30 Oct 2006 11:54 AM
WenYuan Wang
Hi

Just want to check if the issue has been resolved?
If it still persists, please don't hesitate to update here.
We'll go on to assist you on it. Thanks.

Sincerely,
Wen Yuan

AddThis Social Bookmark Button