如何基于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
相关产品推荐
相关产品推荐

