You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于SSOM用C#控制台程序同步SharePoint列表数据至SQL表

嘿,你已经把SSOM连接的基础架子搭好了,接下来咱们一步步把SharePoint的数据同步到数据库里,分两部分来搞定:先处理Headers List到数据库Headers表,再搞定所有文章目录列表到Catalogs表的同步。


1. 同步Headers List到数据库Headers表

首先得把从SharePoint拿到的SPListItemCollection转换成对应数据库的实体,再通过你的XYZ_Entity上下文完成新增或更新操作。

步骤1:写个实体转换辅助方法

假设你已经有了对应数据库Headers表的Header实体类,咱们写个方法把单个SharePoint列表项转成实体(注意SharePoint字段的内部名要和实体字段对应上):

private static Header ConvertToHeaderEntity(SPListItem item)
{
    return new Header
    {
        Id = item.Id,
        TypeOfCatalog = item["_x0160_ifra_x0020_artikla"]?.ToString(),
        CatalogName = item["Naziv_x0020_artikla"]?.ToString(),
        CatalogID = item["Katalog_x002f_ID"]?.ToString(),
        CatalogStatus = item["Status_x0020_kataloga"]?.ToString(),
        CatalogDate = item["Datum_x0020_po_x010d_etka_x0020_"] as DateTime?
        // 剩下的30多个字段依次按这个逻辑映射,注意空值判断
    };
}

步骤2:编写数据库同步逻辑

这里要兼顾初始填充(全量插入)和后续更新(根据主键判断是新增还是覆盖):

private static void SyncHeadersToDatabase(List<Header> headers)
{
    using (var context = new XYZ_Entity())
    {
        foreach (var header in headers)
        {
            var existingHeader = context.Headers.FirstOrDefault(h => h.Id == header.Id);
            if (existingHeader == null)
            {
                // 第一次填充:直接新增
                context.Headers.Add(header);
            }
            else
            {
                // 后续更新:覆盖需要同步的字段
                existingHeader.TypeOfCatalog = header.TypeOfCatalog;
                existingHeader.CatalogName = header.CatalogName;
                existingHeader.CatalogID = header.CatalogID;
                // 其他字段同理更新
            }
        }
        context.SaveChanges();
        Console.WriteLine($"成功同步 {headers.Count} 条Header数据到数据库");
    }
}

步骤3:整合到现有代码里

修改你的Main方法,把转换和同步逻辑加进去:

public static void Main()
{
    string siteURL = "http://somesite.local/sites/promo_tool";
    try
    {
        using (SPSite site = new SPSite(siteURL))
        {
            using (SPWeb web = site.OpenWeb())
            {
                var headerItems = GetSharePointCatalogHeaders(web);
                // 把SharePoint列表项转成实体列表
                var headerEntities = headerItems.Cast<SPListItem>().Select(ConvertToHeaderEntity).ToList();
                // 同步到数据库
                SyncHeadersToDatabase(headerEntities);
                
                Console.WriteLine("Press any key to continue...");
            }
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"错误详情:{ex.Message}");
        PrintErrorSharepointConnection();
        PrintPressKeyToExit();
    }
    finally
    {
        Console.ReadKey();
    }
}

2. 同步文章目录列表到数据库Catalogs表

这部分的核心是先从Headers List里拿到所有文章目录的名称,再逐个遍历这些列表,同步数据到Catalogs表。

步骤1:从Headers List获取所有目录列表名称

假设Headers List里的Naziv_x0020_artikla字段存储的是文章目录列表的名称,写个方法提取这些名称:

private static List<string> GetCatalogListNames(SPWeb web)
{
    var catalogHeaderList = web.Lists.TryGetList("Headers List");
    if (catalogHeaderList == null)
        throw new Exception("Unable to get catalog headers used for checking status of catalogs");
    
    // 只获取需要的字段,减少数据传输
    var query = new SPQuery();
    query.ViewFields = "<FieldRef Name='Naziv_x0020_artikla' />";
    query.ViewFieldsOnly = true;
    
    var items = catalogHeaderList.GetItems(query);
    return items.Cast<SPListItem>()
                .Select(item => item["Naziv_x0020_artikla"]?.ToString())
                .Where(name => !string.IsNullOrEmpty(name))
                .ToList();
}

步骤2:目录数据的转换与同步

同样先写实体转换方法,再写同步逻辑(假设你有对应Catalogs表的Catalog实体):

private static Catalog ConvertToCatalogEntity(SPListItem item)
{
    return new Catalog
    {
        CatalogId = item["CatalogId"]?.ToString(),
        ArticlePrice = decimal.TryParse(item["ArticlePrice"]?.ToString(), out var price) ? price : 0,
        ArticleName = item["ArticleName"]?.ToString(),
        // 剩下的290多个字段按数据类型逐一映射,注意空值和类型转换
    };
}

private static void SyncCatalogToDatabase(string catalogName, List<Catalog> catalogs)
{
    using (var context = new XYZ_Entity())
    {
        foreach (var catalog in catalogs)
        {
            // 根据Catalog表的主键判断是否存在(这里假设CatalogId是主键)
            var existingCatalog = context.Catalogs.FirstOrDefault(c => c.CatalogId == catalog.CatalogId);
            if (existingCatalog == null)
            {
                context.Catalogs.Add(catalog);
            }
            else
            {
                // 更新需要同步的字段
                existingCatalog.ArticlePrice = catalog.ArticlePrice;
                existingCatalog.ArticleName = catalog.ArticleName;
                // 其他字段同理更新
            }
        }
        context.SaveChanges();
        Console.WriteLine($"成功同步 {catalogs.Count} 条{catalogName}目录数据到数据库");
    }
}

步骤3:遍历所有目录列表完成同步

把这部分逻辑加到Main方法里,放在Header同步之后:

public static void Main()
{
    string siteURL = "http://somesite.local/sites/promo_tool";
    try
    {
        using (SPSite site = new SPSite(siteURL))
        {
            using (SPWeb web = site.OpenWeb())
            {
                // 先同步Headers数据
                var headerItems = GetSharePointCatalogHeaders(web);
                var headerEntities = headerItems.Cast<SPListItem>().Select(ConvertToHeaderEntity).ToList();
                SyncHeadersToDatabase(headerEntities);
                
                // 再同步所有文章目录数据
                var catalogListNames = GetCatalogListNames(web);
                foreach (var listName in catalogListNames)
                {
                    var catalogList = web.Lists.TryGetList(listName);
                    if (catalogList == null)
                    {
                        Console.WriteLine($"警告:未找到目录列表 {listName},跳过同步");
                        continue;
                    }
                    
                    // 如果数据量大,建议用SPQuery分页获取,避免内存溢出
                    var query = new SPQuery();
                    // 指定需要的字段,减少数据传输量
                    query.ViewFields = "<FieldRef Name='CatalogId' /><FieldRef Name='ArticlePrice' /><FieldRef Name='ArticleName' />";
                    var catalogItems = catalogList.GetItems(query);
                    
                    var catalogEntities = catalogItems.Cast<SPListItem>().Select(ConvertToCatalogEntity).ToList();
                    SyncCatalogToDatabase(listName, catalogEntities);
                }
                
                Console.WriteLine("所有数据同步完成!Press any key to continue...");
            }
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"错误详情:{ex.Message}");
        PrintErrorSharepointConnection();
        PrintPressKeyToExit();
    }
    finally
    {
        Console.ReadKey();
    }
}

几个关键注意点
  • 字段内部名:SharePoint的字段内部名(比如_x0160_ifra_x0020_artikla)一定要和代码里的对应上,可以通过SharePoint列表设置里的字段URL查看内部名。
  • 大数据量处理:如果某个文章目录列表有上万条数据,直接用GetItems会导致内存问题,建议用SPQuery的RowLimit和Paging属性分批获取。
  • 性能优化:数据库同步时可以用AddRange代替循环Add,减少数据库交互次数;也可以考虑开启EF的批量操作(需要额外包支持)。
  • 错误隔离:给每个目录的同步步骤单独加try-catch,避免一个列表同步失败导致整个程序崩溃。

内容的提问来源于stack exchange,提问作者EagerToLearn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 09:00:14