父类和子类在同一张表

现在出现了父类和子类一般都会存在一张表中,然后设计数据库的时候把父类的ID存到子类另一个字段中就实现了关联。

例如: 网站的左边导航     第一层就可以看做父类,里面就可以看做子类。

我们就先来看看怎么做导航。

效果图:

 

一切为了用户,这个只显示一个下面出来,不要显示多个不然很难看

① 前台页面

 <div >
        <ul id="test" >
        <asp:Repeater ID="replist" runat="server" OnItemDataBound="replist_ItemDataBound">
            <ItemTemplate>
            <li>
                <a class="one" href="javascript:void()"><em><%# Eval("Name")%></em></a>
                <ul style="display: none;">
                    <asp:HiddenField ID="hfId" runat="server" Value='<%# Eval("ID") %>' />
                    <asp:Literal ID="LitFirst" runat="server"></asp:Literal>    //这个标签用来替换数据
                </ul>
            </li>
            </ItemTemplate>
        </asp:Repeater>
        </ul>
    </div>
        <script src="../JS/jquery-1.11.0.min.js"></script>
        <script>
            $("ul#test").on("click", "li", function () {
                //$("ul li ul").css("display", "none");
                if ($(this).hasClass("show")) {
                    $("ul#test li").removeClass("show");
                    Test();
                    //$(this).removeClass("show");
                  //  $(this).find("ul").css("display", "none");
                } else {
                    $("ul#test li").removeClass("show");
                    $(this).addClass("show");
                   Test();
                    //$(this).find("ul").css("display", "block");
                }
            });
          //用来隐藏和显示下面的数据
            function Test()
            {
                $("ul#test li").each(function () {
                    if ($(this).hasClass("show")) {
                        $(this).find("ul").css("display", "block");
                    } else {
                        $(this).find("ul").css("display", "none");
                    }
                });
            }
        </script>

②样式  简单设置一下

    <style>
        ul {
            list-style:none;
        }
        em {
                font-style: normal;
        }
        a {text-decoration:none;
        }
    </style>

③取数据    由于我们搭建的div的原因,想要显示出所有的数据需要用到Repter里面的数据绑定事件

 protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                Binging();
            }
        }

        private void Binging()
        {
            DataSet ds = new FunctionDemo.BLL.Category().GetList("Pid=0");
            replist.DataSource = ds.Tables[0];
            replist.DataBind();
        }

        /// <summary>
        /// 每绑定一行就触发一次  一般这个方法用来加载每一行的子类数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void replist_ItemDataBound(object sender, RepeaterItemEventArgs e)
        {           
            Literal LitFirst = (Literal)e.Item.FindControl("LitFirst");
            HiddenField hfId = (HiddenField)e.Item.FindControl("hfId");
            List<FunctionDemo.Model.Category> cateModel = new FunctionDemo.BLL.Category().GetModelList("Pid=" + hfId.Value);

            foreach (FunctionDemo.Model.Category item in cateModel)
            {
                LitFirst.Text = LitFirst.Text + "<li>"+item.Name+"</li>";
            }
        }

④数据的设计  

父类 Pid=0 子类的Pid就是父类的ID    LevalNum用来表示

第一种父子类就说到这,下面说的是第二种方式 

其中的有个方法值得学习下

 

我们换成下拉框来试试    按分类显示数据  列: 父类 子类   父类  子类  。。

①页面

 <form id="form1" runat="server">
        <asp:DropDownList ID="ddlDemo" runat="server"></asp:DropDownList>
    </form>

②代码

   public FunctionDemo.BLL.Category categoryBLL = new FunctionDemo.BLL.Category();
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                BingDDL();
            }
        }

        public void BingDDL()
        {
            DataTable dt = categoryBLL.GetList("").Tables[0];       //categoryBLL.GetListChild(0, true);
            ddlDemo.Items.Add(new ListItem("类别", "0"));
            foreach (DataRow item in dt.Rows)
            {
                string title = "";
                if (int.Parse(item["LevalNum"].ToString()) > 0)
                {
                    title =" " + "|--" + item["Name"].ToString();
                }
                else
                {
                    title = item["Name"].ToString();
                }
                ddlDemo.Items.Add(new ListItem(title, item["ID"].ToString()));
            }

        }

③显示效果

这一切尽是如此的完美,好像很好一样的。

我们做项目时并不是说所以的东西都是好的,很可能做了一半让你加几条数据,我们来试一试  NBA 加一条 ,爱好加一条,别找我加一条

 我们的数据

然后再显示

我们如何把NBA子类往上面移动呢,这是问题的关键,那么就是查询数据的问题了。

我们改动了取数据的方法

然后显示数据 

 这样很符合我们的要求。

我们来看看这个方法写了什么。

  /// <summary>
        /// 获取全部类别
        /// </summary>
        /// <param name="strWhere">后面的bool值可以显示是否显示禁用的数据,这里并没做处理</param>
        /// <returns></returns>
        public DataTable GetListChild(int PID, bool isState)
        {
            StringBuilder strSql = new StringBuilder();
            strSql.Append("select ID,Name,Pid,LevalNum");
            strSql.Append(" FROM Category ");
            //strSql.Append(" Where ParentId=" + PId);
            if (isState)
            {
                strSql.Append("Where 1=1 ");
            }
            strSql.Append(" order by Id asc");
            DataSet ds = DbHelperSQL.Query(strSql.ToString());      我们的数据查找完了,跟以前是一样的
            DataTable oldData = ds.Tables[0] as DataTable;
            if (oldData == null)
            {
                return null;
            }
            //复制结构
            DataTable newData = oldData.Clone();       clone()是基类Object的方法
            //调用迭代组合成DAGATABLE   用旧数据得到新数据
            GetChannelChild(oldData, newData, PID);

            return newData;
        }


        /// <summary>
        /// 获取子类别
        /// </summary>
        /// <param name="parentId">父编号</param>
        /// <param name="stateInfo">状态</param>
        /// <returns></returns>
        private void GetChannelChild(DataTable oldData, DataTable newData, int PId)
        {
            //第一遍进来的时候是获取父类 pid=0      我们只需每取一条父类数据,然后把改类的子类数据先加载进去就可以了
            DataRow[] dr = oldData.Select("Pid=" + PId);
            for (int i = 0; i < dr.Length; i++)
            {
                //添加一行数据 
                DataRow row = newData.NewRow();  
                row["ID"] = int.Parse(dr[i]["ID"].ToString());
                row["Name"] = dr[i]["Name"].ToString();
                row["Pid"] = dr[i]["Pid"].ToString();
                row["LevalNum"] = dr[i]["LevalNum"].ToString();               
                newData.Rows.Add(row);
                //调用自身迭代
                this.GetChannelChild(oldData, newData, int.Parse(dr[i]["ID"].ToString()));
                //把父类的ID作为条件传进去,子类的数据就会出来
            }
        }

这个方法是一种思想,会的话可以做别的事。

上面是满足我们的原数据和新数据都是在一张表,我们就可以用clone()方法,如果我的新表需要添加字段

   //创建一个新的DataTable,这里可以添加我们的列
            DataTable newData = new DataTable();
            newData.Columns.Add("id", typeof(int));
            newData.Columns.Add("parent_id", typeof(int));
            newData.Columns.Add("class_layer", typeof(int));
            newData.Columns.Add("nav_type", typeof(string));
            newData.Columns.Add("name", typeof(string));
            newData.Columns.Add("title", typeof(string));
            newData.Columns.Add("sub_title", typeof(string));
            newData.Columns.Add("icon_url", typeof(string));
            newData.Columns.Add("link_url", typeof(string));
            newData.Columns.Add("sort_id", typeof(int));
            newData.Columns.Add("is_lock", typeof(int));
            newData.Columns.Add("remark", typeof(string));
            newData.Columns.Add("action_type", typeof(string));
            newData.Columns.Add("is_sys", typeof(int));
             //调用迭代组合成DAGATABLE   用旧数据得到新数据
            GetChannelChild(oldData, newData, PID);

             return newData;
          //在GetChannelChild()这个方法里面的添加数据里面就可以把新列的数据添加进去
原文地址:https://www.cnblogs.com/Sea1ee/p/7028595.html