SharePoint中如何用C#的CAML查询关联两个列表并获取嵌套对象?
首先明确:CAML本身不支持跨列表的JOIN查询并直接返回嵌套结构的结果,因为SharePoint的CAML查询是单列表维度的,没法一次性关联两个列表并返回包含子列表数据的嵌套对象。你需要分两步处理:先查询主列表数据,再批量查询关联的子列表数据,最后在代码层面完成数据的嵌套映射。
以下是具体的C#实现方案(基于SharePoint CSOM):
1. 定义实体类
先定义对应列表数据的实体,方便后续处理:
// Page列表对应的实体 public class PageModel { public int Id { get; set; } public string Title { get; set; } // 嵌套的Fragment列表 public List<FragmentModel> Fragments { get; set; } = new List<FragmentModel>(); } // Fragment列表对应的实体 public class FragmentModel { public int TableAId { get; set; } public string Article { get; set; } }
2. 分两次查询并关联数据
步骤1:查询Page列表的所有数据
using (var ctx = new ClientContext("你的SharePoint站点URL")) { // 根据环境配置认证方式(如用户名密码、App权限等) ctx.Credentials = new SharePointOnlineCredentials("用户名", "密码的SecureString"); // 查询Page列表 var pageList = ctx.Web.Lists.GetByTitle("Page"); var pageQuery = CamlQuery.CreateAllItemsQuery(); var pageItems = pageList.GetItems(pageQuery); ctx.Load(pageItems, items => items.Include( item => item.Id, item => item["Title"] )); ctx.ExecuteQuery(); // 转换为PageModel列表 var pageModels = pageItems.Select(item => new PageModel { Id = item.Id, Title = item["Title"]?.ToString() ?? string.Empty }).ToList();
步骤2:批量查询Fragment列表并关联到对应Page
// 收集所有Page的Id,用于批量过滤Fragment var pageIds = pageModels.Select(p => p.Id).ToList(); if (!pageIds.Any()) { // 没有Page数据,直接返回 return pageModels; } // 构建CAML查询,过滤TableAId在PageIds中的Fragment var fragmentList = ctx.Web.Lists.GetByTitle("Fragment"); var camlBuilder = new StringBuilder(); camlBuilder.Append("<View><Query><Where><In><FieldRef Name='TableAId'/>"); camlBuilder.Append("<Values>"); foreach (var id in pageIds) { camlBuilder.Append($"<Value Type='Number'>{id}</Value>"); } camlBuilder.Append("</Values></In></Where></Query></View>"); var fragmentQuery = new CamlQuery { ViewXml = camlBuilder.ToString() }; var fragmentItems = fragmentList.GetItems(fragmentQuery); ctx.Load(fragmentItems, items => items.Include( item => item["TableAId"], item => item["article"] )); ctx.ExecuteQuery(); // 转换为FragmentModel列表 var fragmentModels = fragmentItems.Select(item => new FragmentModel { TableAId = int.Parse(item["TableAId"].ToString()), Article = item["article"]?.ToString() ?? string.Empty }).ToList();
步骤3:在内存中关联数据,构建嵌套结构
// 将Fragment关联到对应的Page foreach (var page in pageModels) { page.Fragments = fragmentModels.Where(f => f.TableAId == page.Id).ToList(); } // 现在pageModels就是包含嵌套Fragment的Page对象列表 }
补充说明
- 如果你的
TableAId是Lookup类型字段(关联到Page的Id),那么CAML查询中FieldRef的Name要对应Lookup字段的内部名称,并且Value的Type要改为Lookup,同时用LookupId属性指定匹配Id:<Value Type='Lookup' LookupId='True'>{id}</Value> - 这种分两次查询的方式比循环查询每个Page对应的Fragment效率高很多,因为批量查询减少了请求次数。
- 如果你之前尝试用CAML的
<Join>元素,它仅用于在查询主列表时返回关联列表的部分字段(扁平化结果),没法返回嵌套的列表结构,所以无法直接得到你想要的单个嵌套对象。
内容的提问来源于stack exchange,提问作者Mike
相关产品推荐
相关产品推荐

