zoukankan      html  css  js  c++  java
  • 递归同步AD账号

    思路:因为AD本身就是一棵树,而且.Net Framework中提供了对AD的操作对象(DirectoryEntry).该对象包含children和parent属性.所以利用这些属性使用递归算法可以批量生成Insert语句.获得这些SQL语句后,你就可以按照你想要的方式来执行了.

    假设你的部门表有三个字段:DeptID,DeptName,ParentDeptID.根据一般情况,DeptID分类两种类型:整型和GUID类型.DeptName为字符型,ParentDeptID跟DeptID一致.

    先说DeptID为GUID类型:

    这种情况比较简单,因为window os 中的AD存储时,默认使用GUID作为唯一标识.而且DirectoryEntry对象正好包含GUID属性.这样我们就可以方便的遍历出AD中的所有项,而且因为使用递归算法,遍历完生成的SQL已经包含了层级关系.看代码:


    static StringBuilder sbDepts=new StringBuilder ();

    public static string GetBatchSQLFromSRC(DirectoryEntry entry) {

        DirectoryEntries entries 
    = entry.Children;
        
    foreach (DirectoryEntry item in entries){
            sbDepts.Append(
    string.Format("INSERT INTO Ts_Dept(DeptID,DeptName,ParentDeptID) VALUES <br /> ({0},'{1}','{2}') <br />", item.Guid, item.Name, entry.Guid));

                    GetBatchSQLFromSRC(item, intchildDeptID);   
    //递归调用

    }
        
    return sbDepts.ToString();
    }

    这个方法返回一个批量的SQL,可以使用事物来执行这个方法。

    再说DeptID为整型的情况:

    这种情况稍微复杂,因为递归方法本身的特点,一旦某个节点既有子节点又有兄弟节点(确切的说是弟节点),那么就会出现重复的DeptID。为了避免这种情况,需要额外的声明一个静态变量单独存储递归过程中的DeptID最大值。然后使用这个静态变量在递归过程中传递就可以避免重号。


    static StringBuilder sbDepts=new StringBuilder ();

    static int intchildDeptID = 10002;//可做成配置,具体值可以根据实际情况设定

    public static string GetBatchSQLFromSRC(DirectoryEntry entry,int pid) {

        DirectoryEntries entries 
    = entry.Children;
       intchildDeptID 
    = pid == intchildDeptID ? pid + 1 : intchildDeptID;//避免重号
        foreach (DirectoryEntry item in entries){
                 sbDepts.Append(
    string.Format("INSERT INTO Ts_Dept(DeptID,DeptName,ParentID) VALUES ({0},'{1}',{2}) <br />", intchildDeptID, item.Name, pid));
            GetBatchSQLFromSRC(item, intchildDeptID); 
    //递归调用
             }
        
    return sbDepts.ToString();
    }

    下面两个是辅助方法。第一个用来获取指定LDAP路径下的所有节点,另一个是在第一个方法中找特定的节点。

    /// <summary>
    /// 获取AD中指定目录下所有单位
    /// </summary>
    /// <param name="filter">DirectorySearcher的过滤条件</param>
    /// <returns></returns>
    public static SearchResultCollection GetADDepts(string filter) {
        DirectoryEntry entry 
    = new DirectoryEntry(ADDeptPath);
        
    if (entry != null) {
            DirectorySearcher sercher;
            
    try{
                sercher 
    = new DirectorySearcher(entry);
                sercher.Filter 
    = filter;
            }
            
    catch(Exception ex){
                
    throw ex;
            }
            
    return sercher.FindAll();
        }
        
    return null;
    }

    private static readonly string ADDeptPath = ConfigurationManager.AppSettings["ADDept"];//要获取的AD账号的域。

    Config中的配置格式格式:

    <add key="ADDept" value="LDAP://OU=Company,DC=caini,DC=ac,DC=cn"/><!--要同步的单位在AD中的路径-->

     

    /// <summary>
    /// 获取指定LDAP路径对应的AD对象
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    public static DirectoryEntry GetDirectotyEntryInCollection(string path) {
        
    foreach (SearchResult result in GetADDepts()) {
            
    if (result.Path == path){             
                
    return result.GetDirectoryEntry();
            }
        }
        
    return null;
    }

    为了方便客户端代码调用,可以把递归方法封装一下。下面只封装了GUID类型的,整型的大家可以自己试着封装一下。如下:

    /// <summary>
    /// 从域中获取
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    public static string GetBatchSQLFromSRC(string path) {
        sbDepts.Length 
    = 0;
        
    //SearchResult result = GetSearchResultInCollection(path);
        DirectoryEntry entry = GetDirectotyEntryInCollection(path);
        
    int rootdeptid = 10001;
        
    //return GetBatchSQLFromSRC(entry);
        return GetBatchSQLFromSRC(entry, rootdeptid);
    }

    这样客户端代码只要传递一个合法的LDAP路径,就可以获取该路径下所有的节点。

    例如:

    protected void Page_Load(object sender, EventArgs e)
    {
        
    if (!this.IsPostBack) {
            
    string path = "LDAP://OU=NewDept1,OU=Company,DC=caini,DC=ac,DC=cn";
            
    string ret = ADHelper.GetBatchSQLFromSRC(path);
            Response.Clear();
            Response.Write(ret);
            Response.End();
        }
    }

    注意:以上代码要引入

    1.using System.DirectoryServices;命名空间
    2.注意红体部门,为了灵活在web.config中做了配置

    以上代码要引入

    至于性能这块暂时还没考虑,如果大家有什么更好的办法请不吝赐教。

  • 相关阅读:
    Quicksum -SilverN
    uva 140 bandwidth (好题) ——yhx
    uva 129 krypton factors ——yhx
    uva 524 prime ring problem——yhx
    uva 10976 fractions again(水题)——yhx
    uva 11059 maximum product(水题)——yhx
    uva 725 division(水题)——yhx
    uva 11853 paintball(好题)——yhx
    uva 1599 ideal path(好题)——yhx
    uva 1572 self-assembly ——yhx
  • 原文地址:https://www.cnblogs.com/jjhe369/p/2042032.html
Copyright © 2011-2022 走看看