【问题标题】:How to filter 2 comboboxes based on the selection in 1 combobox?如何根据 1 个组合框中的选择过滤 2 个组合框?
【发布时间】:2019-05-26 10:26:20
【问题描述】:

我有 3 张桌子:

1) 房子:

| ID_house | House_names | num_region |
---------------------------------------
|   int    |    names    |    int     |

num_region - 外键,相当于Region表中的主键(Region.ID_region)。

2) 地区:

| ID_region | Nameofregions | num_arearegion |
---------------------------------------------
|   int     |    names      |      int       |

num_arearegion - 外键,等于 Areas_InRegion 表中的主键(Areas_InRegion.ID_areas)。

3) Areas_InRegion:

| ID_areas | Area_names |
------------------------
|   int   |    names   |

在表单中我有 3 个组合框:

1) cmbHouse - 用于显示 House 表中的房屋名称。

2) cmbRegion - 用于显示 Region 表中的区域名称。

3) cmbArea - 用于显示 Areas_InRegion 表中区域中的区域名称。

我这样填充组合框:

    //cmbHouse
    string cmbHouse_query = "SELECT * FROM House";
    OleDbDataAdapter dahouse = new OleDbDataAdapter(cmbHouse_query, connection);
    DataTable tablehouse = new DataTable();
    dahouse.Fill(tablehouse);
    cmbHouse.DataSource = tablehouse;
    cmbHouse.DisplayMember = "House_names"; 
    cmbHouse.ValueMember = "House.num_region";
    cmbHouse.SelectedIndex = -1;

    //cmbRegion
    string cmbRegion_query = "SELECT * FROM Region";
    OleDbDataAdapter daregion = new OleDbDataAdapter(cmbRegion_query, connection);
    DataTable tableregion = new DataTable();
    daregion.Fill(tableregion);
    cmbRegion.DataSource = tableregion;
    cmbRegion.DisplayMember = "Nameofregions";
    cmbRegion.ValueMember = "Region.ID_region";
    cmbRegion.SelectedIndex = -1;

    //cmbArea
    string cmbArea_query = "SELECT * FROM Areas_InRegion";
    OleDbDataAdapter daArea = new OleDbDataAdapter(cmbArea_query, connection);
    DataTable tablearea = new DataTable();
    daArea.Fill(tablearea);
    cmbArea.DataSource = tablearea;
    cmbArea.DisplayMember = "Names_OfAreas";
    cmbArea.ValueMember = "Areas_InRegion.ID_areas";
    cmbArea.SelectedIndex = -1;

Combobox cmbRegion 有 valuemember 作为主键。

我可以通过主键过滤 cmbHouse 组合框作为 cmbRegion 组合中的 valuemeber,但我不能过滤 cmbArea 组合框。

    private void cmbHouse_SelectionChangeCommitted(object sender, EventArgs e)
    {
        if (cmbHouse.SelectedIndex > -1)
        {
            //DataRow selectedDataRow = ((DataRowView)cmbHouse.SelectedItem).Row;
            int num_region = Convert.ToInt32(cmbHouse.SelectedValue);

            OleDbCommand com = new OleDbCommand();
            com.CommandText = "SELECT * FROM Region WHERE Region.ID_region=" + num_region.ToString() + "";
            //com.Parameters.AddWithValue("House.num_region", typeof(int));
            OleDbDataAdapter danum_region = new OleDbDataAdapter(com.CommandText, connection);
            DataTable tablenum_region = new DataTable();
            danum_region.Fill(tablenum_region);
            cmbRegion.DataSource = tablenum_region;
            cmbRegion.DisplayMember = "Nameofregions";
            cmbRegion.ValueMember = "Region.num_arearegion";
            //cmbRegion.SelectedIndex = -1;
            if(cmbRegion.SelectedIndex > -1)
            {
                int num_area = Convert.ToInt32(cmbRegion.SelectedValue);

                OleDbCommand com2 = new OleDbCommand();

                com2.CommandText = "SELECT * FROM Areas_InRegion WHERE Areas_InRegion.ID_areas=" + num_area.ToString(); // + num_area.ToString() + " ; WHERE Region.num_arearegion=@Areas_InRegion.ID_area
                                                                                                                        //com2.Parameters.AddWithValue("@Areas_InRegion.ID_area", num_area);
                OleDbDataAdapter danum_area = new OleDbDataAdapter(com2.CommandText, connection);
                DataTable tablenum_area = new DataTable();
                //tablenum_area.DefaultView.RowFilter = "Areas_InRegion.ID_areas=" + num_area.ToString();
                danum_area.Fill(tablenum_area);

                cmbArea.DataSource = tablenum_area;
                cmbArea.DisplayMember = "Names_OfAreas";
                cmbArea.ValueMember = "Areas_InRegion.ID_areas";
                //cmbArea.SelectedIndex = -1;
            }
        }                
    }

为此,必须有另一个 valuemeber 作为外键 [Region.num_areas]。

是否可以在每个组合框中有多个值成员?

当我点击任何组合框时,其他组合框应该被过滤掉。

请帮帮我。

谢谢。

【问题讨论】:

  • 让我了解你们的关系。 房子位于一个区域(1-1 关系),一个 Region 可以有一个或多个 Areas(1-n 关系),一个 Area 属于一个且只有一个 Region。 我看你是在这个问题上停留了几天,你已经问了很多关于这个选择问题的问题,但如果我是对的,你需要在之前纠正你的关系。
  • @Steve 房子位于一个区域(1-1 关系),一个Region 可以有一个或多个Areas(1-n 关系),一个Area 属于一个且仅一个Region。 - 是正确的。
  • 表之间的关系是正确的,但是组合框可以包含多个值成员吗?
  • 不,没有这样的功能。但是您的表格不正确。表Region中num_arearegion是什么意思?并且表区域需要表区域的外键来指示区域的所有者区域。如果你想在选择房子时选择一个区域,那么你需要在表 House 中也有该区域的外键

标签: c# database winforms combobox oledb


【解决方案1】:

一栋房子位于一个区域(1-1 关系),一个区域可以有一个或多个区域(1-n 关系),一个区域属于一个且仅一个区域关系您的数据库架构错误。你需要这样的东西(因为显然一所房子只能位于一个区域)

1) House:
| ID_house | House_names | ID_region | ID_areas |
--------------------------------------------------
|   int    |    names    |    int     | int      |

2) Region:
| ID_region | Nameofregions |
-----------------------------
|   int     |    names      |

3) Areas:
| ID_areas | Area_names | ID_region |
-------------------------------------
|   int   |    names    | int       |

现在,当您获得房屋的 id 时,您还获得了地区和区域的 id。

private void cmbHouse_SelectionChangeCommitted(object sender, EventArgs e)
{
    if (cmbHouse.SelectedIndex > -1)
    {
        // Each item in a combobox binded to a datatable is a DataRowView
        // If we get this object we can access all the columns from that row
        DataRowView rv = cmbHouse.SelectedItem as DataRowView;

        // Extract the fk for the region and the area
        int id_region = Convert.ToInt32(rv["ID_region"]);
        int id_area = Convert.ToInt32(rv["ID_area"]);

        // at startup you have already filled the combo with the regions,
        // so there is no need to look again in the database for the region
        // Just set the current selected value to the region
        cmbRegion.SelectedValue = num_region;

        // the same happens for the Areas combo. It is already filled with the 
        // areas, but here we should really have only the areas that belongs to 
        // the selected region not all the area to avoid problems 
        // (so remove the initial filling and do it only when the user choose an House)
        // Query for all areas belonging to the selected region
        string areaSql = @"SELECT * FROM Areas 
                           WHERE ID_Region=@reg";
        OleDbCommand com2 = new OleDbCommand(areaSql, connection);
        com2.Parameters.AddWithValue("@reg", num_region);
        OleDbDataAdapter danum_area = new OleDbDataAdapter(com2);
        DataTable tablenum_area = new DataTable();
        danum_area.Fill(tablenum_area);

        // Always put the Datasource after the setting for DisplayMember and ValueMember 
        // to avoid performance drops and problems if there is a SelectedIndexChanged event
        cmbArea.DisplayMember = "Names_OfAreas";
        cmbArea.ValueMember = "ID_areas";
        cmbArea.DataSource = tablenum_area;

        // last step is setting the SelectedValue on the cmbArea to the house's area 
        cmbArea.SelectedValue = id_area;
    }
}

【讨论】:

  • 这个符号“@”在查询中是什么意思? Parameters.AddWithValue 执行什么功能?
  • 命令文本中的@符号是参数占位符。数据库接收参数并应用正确的逻辑以在请求的数据操作中使用参数值。将参数添加到命令的参数集合可以帮助您避免繁琐的字符串连接,这些连接通常用于使用称为 Sql Injection 的技术来破解数据库。参数还避免了解析问题,例如正确解释日期和十进制值。此外,如果命令文本是固定的,数据库引擎可以重用以前解析过的查询,从而提高性能。
猜你喜欢
  • 2018-11-07
  • 2013-04-25
  • 2018-08-10
  • 2021-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多