zoukankan      html  css  js  c++  java
  • 【树结构数据同步】公司部门—通讯录数据同步

    • 需求

    将本地公司部门信息更新到微信企业号通讯录(可改进为定期更新)

    • 说明

    保存在本地数据库的公司部门信息,采用类似如下格式保存:

    UCNameUCIDParentUCID
    A 1001000  
    B 1002000  
    A1 1001100 1001000
    A2 1001200 1001000
    A11 1001110 1001100
    ......

    由于UCID为字符串格式,而通讯录保存的公司部门ID为int类型,所以上传到企业号通讯录的公司部门信息会形成新的ID。这就形成了同一部门在本地、通讯录各有各的ID、父ID。

    • 解决方案

    为保证部门结构关系同步准确,对部门数据进行树形结构化,由于部门信息,部门名可能存在同名,但同一部门下不存在同名的子部门,所以对各节点进行部门名、父节点关系进行匹对,以确定两棵部门树最终一致(ID和父ID不同)。
    同时建立一“公司-通讯录”部门映射表。


    原始本地『公司部门树』如下:



    上传后的『通讯录部门树』如下:

    『公司—通讯录部门映射表』数据:

    UCNameDPIDParentDPIDUCIDParentUCID
    A 2 1 1001000  
    B 3 1 1002000  
    A1 4 2 1001100 1001000
    A2 5 2 1001200 1001000
    A11 6 4 1001110 1001100

    树结构:

    【部门数据变化】
    当本地公司部门信息改变后,本地部门树如下:


    新增部门数(橘红色):4
    更新部门数(橘黄色):1(含1子部门)


    由于有新部门父节点也是新增部门,为保证父子部门关系正确,对新增部门的同步化采用:先添加新增部门,再确定父部门编号。

    将公司部门表与映射表进行匹对,向映射表添加新的部门信息,形成如下树结构:

    这里看到在A部门下的A1部门还未同步,于是更新A1部门父节点信息,形成最终树结构:

    至此,同步好通讯录部门树。

    • 相关代码

     主程序:

    class DeptTree_Test
    {
        static void Main(string[] args)
        {
            TreeNode rootUC = new TreeNode()
            {
                NName = "组织",
                NID = "1",
                ParentNID = ""
            };
            TreeNode rootDept = new TreeNode()
            {
                NName = "组织",
                NID = "1",
                ParentNID = ""
            };
    
            DeptTree_Test p = new DeptTree_Test();
            p.InitUC(); // 模拟从本地数据库读取公司部门信息
            Console.WriteLine("===========公司部门===========");
            p.PrintTree(rootUC, LocalUC);   // 生成打印出公司部门树
    
            p.InitDept();   // 模拟从通讯录下载部门信息
            Console.WriteLine("===========通讯录===========");
            p.PrintTree(rootDept, Dept);    // 生成打印出通讯录部门树
    
            rootDept.ChildrenNode.Clear();
            p.MakeMap();    // 模拟读取『公司-通讯录』部门映射表
            Console.WriteLine("===========映射表===========");
            p.PrintTree(rootDept, Map); // 生成打印出映射表部门树
    
    
            rootUC.ChildrenNode.Clear();
            p.ChangeUC();   // 模拟公司部门信息更新
            Console.WriteLine("===========公司部门改变===========");
            p.PrintTree(rootUC, LocalUC);   // 生成打印出新的公司部门树
    
    
            Console.WriteLine("===========映射表增量变化===========");
            var ltNewOU = p.treeManager.Subtract(rootUC, rootDept, TreeManager.MatchTag.NName); // 获取本地公司部门与映射表部门差异部门信息
            List<DataRow> lToFixNewDP = new List<DataRow>();
            // 先新增
            foreach (var ou in ltNewOU)
            {
                //Console.WriteLine("{?} - {?},{?}({?})".Format_Ext(ou.NName, ou.NID, ou.ParentNID, JsonConvert.SerializeObject(ou.ExtraInfo)));
                if (ou.ExtraInfo["Extra_DiffType"].ToString() == "MISSING")     // 映射表中缺失的公司新增部门
                {
                    DataRow nDr = Map.NewRow();
                    nDr[0] = ou.NName;
                    nDr[1] = p.autoIncreaseID++;    // 模拟预新增通讯录部门ID
    
                    nDr[3] = ou.NID;
                    nDr[4] = ou.ParentNID;
    
                    Map.Rows.Add(nDr);
    
                    lToFixNewDP.Add(nDr);
                }
            }
            // 然后确定父节点
            foreach (DataRow mr in Map.Rows)
            {
                if (!lToFixNewDP.Exists(_d => _d[1].ToString() == mr[1].ToString())) continue;
    
                foreach (DataRow r in Map.Rows)
                {
                    if (r["Extra_UCID"].ToString() == mr[4].ToString())
                    {
                        mr[2] = r[1];
                    }
                }
    
                // 这里可以调用API添加到企业号(或先临时保存新增部门信息,后面统一更新)
            }
    
            rootDept.ChildrenNode.Clear();
            p.PrintTree(rootDept, Map); // 打印出增量变化后的映射表部门树
    
            Console.WriteLine("===========映射表父节点变化===========");
            foreach (var ou in ltNewOU)
            {
                if (ou.ExtraInfo["Extra_DiffType"].ToString() == "DIFFERENT")
                {
                    foreach (DataRow dr in Map.Rows)
                    {
                        if (dr["Extra_UCID"].ToString() == ou.NID)
                        {
                            foreach (DataRow pdr in Map.Rows)
                            {
                                if (pdr["Extra_UCID"].ToString() == ou.ParentNID)
                                {
                                    dr[2] = pdr[1];
    
                                    // 这里可以调用API更新到企业号(或先临时保存变化的部门信息,后面统一更新)
                                }
                            }
                        }
                    }
                }
            }
    
            rootDept.ChildrenNode.Clear();
            p.PrintTree(rootDept, Map); // 打印出父节点调节后的映射表部门树
    
            //// 移除通讯录上多余的部门
            //var ltToRmvDept = p.treeManager.Subtract(rootDept, rootUC, TreeManager.MatchTag.NName);
    
            Console.WriteLine("Done");
            Console.ReadKey();
        }
    
    
        TreeManager treeManager = new TreeManager();
    
        public static DataTable Dept = new DataTable();
        public static DataTable LocalUC = new DataTable();
        public static DataTable Map = new DataTable();
    
        int autoIncreaseID = 7;
    
        void InitUC()
        {
            LocalUC.Columns.Add("NName");
            LocalUC.Columns.Add("NID");
            LocalUC.Columns.Add("ParentNID");
    
            DataRow nDr = LocalUC.NewRow();
            nDr[0] = "A"; nDr[1] = "1001000"; nDr[2] = "";
            LocalUC.Rows.Add(nDr);
    
            nDr = LocalUC.NewRow();
            nDr[0] = "B"; nDr[1] = "1002000"; nDr[2] = "";
            LocalUC.Rows.Add(nDr);
    
            nDr = LocalUC.NewRow();
            nDr[0] = "A1"; nDr[1] = "1001100"; nDr[2] = "1001000";
            LocalUC.Rows.Add(nDr);
    
            nDr = LocalUC.NewRow();
            nDr[0] = "A2"; nDr[1] = "1001200"; nDr[2] = "1001000";
            LocalUC.Rows.Add(nDr);
    
            nDr = LocalUC.NewRow();
            nDr[0] = "A11"; nDr[1] = "1001110"; nDr[2] = "1001100";
            LocalUC.Rows.Add(nDr);
        }
        void ChangeUC()
        {
            LocalUC.Rows[2][2] = "1002000";
    
            DataRow nDr = LocalUC.NewRow();
            nDr[0] = "A3"; nDr[1] = "1001300"; nDr[2] = "1001000";
            LocalUC.Rows.Add(nDr);
    
            nDr = LocalUC.NewRow();
            nDr[0] = "A21"; nDr[1] = "1001210"; nDr[2] = "1001200";
            LocalUC.Rows.Add(nDr);
    
            nDr = LocalUC.NewRow();
            nDr[0] = "A211"; nDr[1] = "1001211"; nDr[2] = "1001210";
            LocalUC.Rows.Add(nDr);
    
            nDr = LocalUC.NewRow();
            nDr[0] = "B1"; nDr[1] = "1002100"; nDr[2] = "1002000";
            LocalUC.Rows.Add(nDr);
        }
    
        void InitDept()
        {
            Dept.Columns.Add("NName");
            Dept.Columns.Add("NID");
            Dept.Columns.Add("ParentNID");
    
            DataRow nDr = Dept.NewRow();
            nDr[0] = "A"; nDr[1] = "2"; nDr[2] = "";
            Dept.Rows.Add(nDr);
    
            nDr = Dept.NewRow();
            nDr[0] = "B"; nDr[1] = "3"; nDr[2] = "";
            Dept.Rows.Add(nDr);
    
            nDr = Dept.NewRow();
            nDr[0] = "A1"; nDr[1] = "4"; nDr[2] = "2";
            Dept.Rows.Add(nDr);
    
            nDr = Dept.NewRow();
            nDr[0] = "A2"; nDr[1] = "5"; nDr[2] = "2";
            Dept.Rows.Add(nDr);
    
            nDr = Dept.NewRow();
            nDr[0] = "A11"; nDr[1] = "6"; nDr[2] = "4";
            Dept.Rows.Add(nDr);
        }
    
        void MakeMap()
        {
            Map = new DataTable();
            Map.Columns.Add("NName");
            Map.Columns.Add("NID");
            Map.Columns.Add("ParentNID");
            Map.Columns.Add("Extra_UCID");
            Map.Columns.Add("Extra_ParentUCID");
    
            foreach (DataRow dp in Dept.Rows)
            {
                DataRow nDr = Map.NewRow();
                nDr[0] = dp[0];
                nDr[1] = dp[1];
                nDr[2] = dp[2];
    
                foreach (DataRow uc in LocalUC.Rows)
                {
                    if (uc[0] == dp[0])
                    {
                        nDr[3] = uc[1];
                        nDr[4] = uc[2];
                        break;
                    }
                }
    
                Map.Rows.Add(nDr);
            }
        }
    
        void PrintTree(TreeNode root, DataTable dt)
        {
            treeManager.BuildTree("", root, dt, 0);
            var lst = treeManager.Traverse(root);
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(lst[0].NName);
            for (int i = 1; i < lst.Count; i++)
            {
                var item = lst[i];
    
                string str = "";
                for (int j = 0; j <= item.DeepIndex; j++)
                {
                    str += "	";
                }
    
                if (item.ExtraInfo.Count == 0)
                {
                    sb.AppendLine(str + item.NName + "(" + item.NID + ")");
                }
                else
                {
                    sb.AppendLine(str + item.NName + "(" + item.NID + ":" + item.ExtraInfo.ElementAt(0).Value.ToString() + ")");
                }
            }
            Console.WriteLine(sb.ToString());
        }
    
    }
    

    树算法类:

    public class TreeManager
    {
        public enum MatchTag
        {
            NID,
            NName
        }
    
        public class ExtraInfo
        {
            public string Key = "";
            public object Value = "";
        }
    
        public int TreeDeep = 0;
        public void BuildTree(string parentNID, TreeNode tn, DataTable dt, int dp)
        {
            if (dp > 100) throw new Exception("Too Deep!");
            if (dp > TreeDeep) TreeDeep = dp;
    
            foreach (DataRow dr in dt.Rows)
            {
                if ((parentNID == null && dr["ParentNID"] == null)
                    || (parentNID != null && dr["ParentNID"].ToString() == parentNID))
                {
                    var o = new TreeNode()
                    {
                        NID = dr["NID"].ToString().Trim(),
                        NName = dr["NName"].ToString().Trim(),
                        ParentNID = parentNID,
                        DeepIndex = dp
                    };
                    foreach (DataColumn dc in dt.Columns)
                    {
                        if (dc.ColumnName.StartsWith("Extra_"))
                        {
                            o.ExtraInfo.Add(dc.ColumnName, dr[dc.ColumnName]);
                        }
                    }
                    o.ParentNode = tn;
                    tn.ChildrenNode.Add(o);
    
                    BuildTree(o.NID, o, dt, dp + 1);
                }
            }
        }
    
        public TreeNode FindInTree(TreeNode tnode, string nid, string nname, ExtraInfo extraInfo)
        {
            if (tnode == null) return null;
    
            TreeNode tn = null;
            if (tn == null && !string.IsNullOrEmpty(nid))
            {
                if (tnode.NID == nid) tn = tnode;
            }
            if (tn == null && !string.IsNullOrEmpty(nname))
            {
                if (tnode.NName == nname) tn = tnode;
            }
            if (tn == null && extraInfo != null)
            {
                foreach (string k in tnode.ExtraInfo.Keys)
                {
                    if (k == extraInfo.Key
                        && extraInfo.Value.ToString() == tnode.ExtraInfo[k].ToString())
                    {
                        tn = tnode;
                        return tn;
                    }
                }
            }
            if (tn == null && tnode.ChildrenNode.Count > 0)
            {
                foreach (var item in tnode.ChildrenNode)
                {
                    tn = FindInTree(item, nid, nname, extraInfo);
                    if (tn != null) break;
                }
            }
    
            return tn;
        }
    
        /// <summary>
        /// 匹配树结构
        /// </summary>
        /// <param name="root1"></param>
        /// <param name="root2"></param>
        /// <param name="mt">根据节点ID/节点名称进行匹对</param>
        /// <returns></returns>
        public List<TreeNode> Subtract(TreeNode root1, TreeNode root2, MatchTag mt = MatchTag.NID)
        {
            List<TreeNode> lTN = new List<TreeNode>();
    
            var lPath1 = Traverse(root1);
            var lPath2 = Traverse(root2);
    
            bool pass = false;
            foreach (var item in lPath1)
            {
                pass = false;
                for (int i = 0; i < lPath2.Count; i++)
                {
                    if (mt == MatchTag.NID)
                    {
                        if (lPath2[i].NID == item.NID)
                        {
                            if (((lPath2[i].ParentNode != null && item.ParentNode != null && lPath2[i].ParentNode.NID == item.ParentNode.NID)
                               || lPath2[i].ParentNode == null && item.ParentNode == null))
                            {
                                lPath2.RemoveAt(i--);
                                pass = true;
                                break;
                            }
    
                            item.ExtraInfo.Add("Extra_DiffType", "DIFFERENT");
                        }
                    }
                    else if (mt == MatchTag.NName)
                    {
                        if (lPath2[i].NName == item.NName)
                        {
                            if (((lPath2[i].ParentNode != null && item.ParentNode != null && lPath2[i].ParentNode.NName == item.ParentNode.NName)
                               || lPath2[i].ParentNode == null && item.ParentNode == null))
                            {
                                lPath2.RemoveAt(i--);
                                pass = true;
                                break;
                            }
    
                            item.ExtraInfo.Add("Extra_DiffType", "DIFFERENT");
                        }
                    }
                }
                if (!pass)
                {
                    if (!item.ExtraInfo.ContainsKey("Extra_DiffType"))
                        item.ExtraInfo.Add("Extra_DiffType", "MISSING");
    
                    lTN.Add(item);
                }
            }
    
            return lTN;
        }
    
        /// <summary>
        /// 遍历树(纵向)
        /// </summary>
        /// <param name="root"></param>
        /// <returns></returns>
        public List<TreeNode> Traverse(TreeNode root)
        {
            List<TreeNode> lPath = new List<TreeNode>();
    
            lPath.Add(root);
            if (root.ChildrenNode.Count > 0)
            {
                foreach (var item in root.ChildrenNode)
                {
                    foreach (var n in Traverse(item))
                    {
                        lPath.Add(n);
                    }
                }
            }
    
            return lPath;
        }
    
        /// <summary>
        /// 遍历树(横向)
        /// </summary>
        /// <param name="root"></param>
        /// <returns></returns>
        public List<TreeNode> TraverseByLayer(TreeNode root)
        {
            List<TreeNode> lPath = new List<TreeNode>();
    
            lPath.Add(root);
    
            TreeNode tn = root;
            Queue<TreeNode> qToTraverseTN = new Queue<TreeNode>();
            List<TreeNode> lToTraverseTN = new List<TreeNode>();
            do
            {
                foreach (var item in tn.ChildrenNode)
                {
                    lPath.Add(item);
    
                    qToTraverseTN.Enqueue(item);
                }
    
                if (qToTraverseTN.Count == 0) break;
                tn = qToTraverseTN.Dequeue();
            } while (true);
    
            return lPath;
        }
    
    }
    
    public class TreeNode
    {
        public int DeepIndex = 0;
    
        public string NID;
        public string NName;
        public string ParentNID;
    
        public Dictionary<string, object> ExtraInfo = new Dictionary<string, object>();
    
        public TreeNode ParentNode = null;
        public List<TreeNode> ChildrenNode = new List<TreeNode>();
    
        public int TotalChildrenNodeCount()
        {
            int childrenOUTotalCount = ChildrenNode.Count;
    
            foreach (var item in ChildrenNode)
            {
                int tc = item.TotalChildrenNodeCount();
    
                childrenOUTotalCount += tc;
            }
    
            return childrenOUTotalCount;
        }
    }
    
  • 相关阅读:
    tinymce原装插件源码分析(二)-link
    tinymce原装插件源码分析(一)-hr
    pyinstall 常见错误
    matlab Time-domain analysis 渐进式或者实时获取仿真值
    初识python和pycharm
    自定义指令详解
    Vue核心知识一览
    多维数组 转化为 一维数组
    js面试之数组的几个不low操作
    js如何操作或是更改sass里的变量
  • 原文地址:https://www.cnblogs.com/glife/p/5846065.html
Copyright © 2011-2022 走看看