具有多个字段的嵌套 AND 和 OR 的 CAML 查询

Posted

技术标签:

【中文标题】具有多个字段的嵌套 AND 和 OR 的 CAML 查询【英文标题】:CAML query with nested ANDs and ORs for multiple fields 【发布时间】:2011-09-06 10:11:35 【问题描述】:

我正在研究概念验证代码,以根据提供给我正在编写的高度特定的搜索 Web 服务的关键字动态生成 CAML。我没有使用 SharePoint 提供的搜索 Web 服务来证明这一点。我已经为我想要实现的目标这样做了。从我所有的研究中,我找不到我想要实现的一个紧密的例子,即检查多个字段的多个值。是的,我已经在寻找答案了,包括这个:Need help on building CAML Query。

话虽如此,如果可能的话,如何用 CAML 编写以下类似 SQL 的查询?

SELECT FirstName, LastName, Description, Profile
FROM SomeFakeTable
WHERE (FirstName = 'John' OR LastName = 'John' OR Description = 'John' OR Profile='John')
  AND (FirstName = 'Doe' OR LastName = 'Doe' OR Description = 'Doe' OR Profile='Doe')
  AND (FirstName = '123' OR LastName = '123' OR Description = '123' OR Profile='123')

【问题讨论】:

【参考方案1】:

由于不允许在一个条件组中放置两个以上的条件(And | Or),因此您必须创建一个额外的嵌套组(MSDN)。表达式A AND B AND C 如下所示:

<And>
    A
    <And>
        B
        C
    </And>
</And>

您的类似 SQL 的示例已翻译为 CAML(希望带有匹配的 XML 标记;)):

<Where>
    <And>
        <Or>
            <Eq>
                <FieldRef Name='FirstName' />
                <Value Type='Text'>John</Value>
            </Eq>
            <Or>
                <Eq>
                    <FieldRef Name='LastName' />
                    <Value Type='Text'>John</Value>
                </Eq>
                <Eq>
                    <FieldRef Name='Profile' />
                    <Value Type='Text'>John</Value>
                </Eq>
            </Or>
        </Or>
        <And>       
            <Or>
                <Eq>
                    <FieldRef Name='FirstName' />
                    <Value Type='Text'>Doe</Value>
                </Eq>
                <Or>
                    <Eq>
                        <FieldRef Name='LastName' />
                        <Value Type='Text'>Doe</Value>
                    </Eq>
                    <Eq>
                        <FieldRef Name='Profile' />
                        <Value Type='Text'>Doe</Value>
                    </Eq>
                </Or>
            </Or>
            <Or>
                <Eq>
                    <FieldRef Name='FirstName' />
                    <Value Type='Text'>123</Value>
                </Eq>
                <Or>
                    <Eq>
                        <FieldRef Name='LastName' />
                        <Value Type='Text'>123</Value>
                    </Eq>
                    <Eq>
                        <FieldRef Name='Profile' />
                        <Value Type='Text'>123</Value>
                    </Eq>
                </Or>
            </Or>
        </And>
    </And>
</Where>

【讨论】:

谢谢,杰森!我回来访问我的问题以提供答案,因为我自己想通了。但是,我很高兴看到您的回答与我的结果相符,非常感谢您花时间帮助我和其他 SO 用户。 感谢您的帖子。您的示例 XML 提供了一种很好的方法来仔细检查嵌套语法。我用它想出了这个生成equivalent to the In operator的方法【参考方案2】:

你可以试试 U2U Query Builder http://www.u2u.net/res/Tools/CamlQueryBuilder.aspx 你可以使用他们的 API U2U.SharePoint.CAML.Server.dll 和 U2U.SharePoint.CAML.Client.dll

我没有使用它们,但我相信它会帮助您完成任务。

【讨论】:

您不应该在此处发布解决方案,除非您知道它可以提供所要求的结果。使用 U2U 工具可以节省大量时间,但您应该提供它生成的代码的工作示例。【参考方案3】:

此代码将使用嵌套子句为您动态生成表达式。我有一个场景,其中 "OR" 的数量是未知的,所以我使用下面的。用法:

        private static void Main(string[] args)
        
            var query = new PropertyString(@"<Query><Where>WhereClauses</Where></Query>");
            var whereClause =
                new PropertyString(@"<Eq><FieldRef Name='ID'/><Value Type='Counter'>NestClauseValue</Value></Eq>");
            var andClause = new PropertyString("<Or>FirstExpressionSecondExpression</Or>");

            string[] values = "1", "2", "3", "4", "5", "6";

            query["WhereClauses"] = NestEq(whereClause, andClause, values);

            Console.WriteLine(query);
        

这是代码:

   private static string MakeExpression(PropertyString nestClause, string value)
        
            var expr = nestClause.New();
            expr["NestClauseValue"] = value;
            return expr.ToString();
        

        /// <summary>
        /// Recursively nests the clause with the nesting expression, until nestClauseValue is empty.
        /// </summary>
        /// <param name="whereClause"> A property string in the following format: <Eq><FieldRef Name='Title'/><Value Type='Text'>NestClauseValue</Value></Eq>"; </param>
        /// <param name="nestingExpression"> A property string in the following format: <And>FirstExpressionSecondExpression</And> </param>
        /// <param name="nestClauseValues">A string value which NestClauseValue will be filled in with.</param>
        public static string NestEq(PropertyString whereClause, PropertyString nestingExpression, string[] nestClauseValues, int pos=0)
        
            if (pos > nestClauseValues.Length)
            
                return "";
            

            if (nestClauseValues.Length == 1)
            
                return MakeExpression(whereClause, nestClauseValues[0]);
            

            var expr = nestingExpression.New();
            if (pos == nestClauseValues.Length - 2)
            
                expr["FirstExpression"] = MakeExpression(whereClause, nestClauseValues[pos]);
                expr["SecondExpression"] = MakeExpression(whereClause, nestClauseValues[pos + 1]);
                return expr.ToString();
            
            else
            
                expr["FirstExpression"] = MakeExpression(whereClause, nestClauseValues[pos]);
                expr["SecondExpression"] = NestEq(whereClause, nestingExpression, nestClauseValues, pos + 1);
                return expr.ToString();
            
        






          public class PropertyString
    
        private string _propStr;

        public PropertyString New()
        
            return new PropertyString(_propStr );
        

        public PropertyString(string propStr)
        
            _propStr = propStr;
            _properties = new Dictionary<string, string>();
        

        private Dictionary<string, string> _properties;
        public string this[string key]
        
            get
            
                return _properties.ContainsKey(key) ? _properties[key] : string.Empty;
            
            set
            
                if (_properties.ContainsKey(key))
                
                    _properties[key] = value;
                
                else
                
                    _properties.Add(key, value);
                
            
        



        /// <summary>
        /// Replaces properties in the format propertyName in the source string with values from KeyValuePairPropertiesDictionarysupplied dictionary.nce you've set a property it's replaced in the string and you 
        /// </summary>
        /// <param name="originalStr"></param>
        /// <param name="keyValuePairPropertiesDictionary"></param>
        /// <returns></returns>
        public override string ToString()
        
            string modifiedStr = _propStr;
            foreach (var keyvaluePair in _properties)
            
                modifiedStr = modifiedStr.Replace("" + keyvaluePair.Key + "", keyvaluePair.Value);
            

            return modifiedStr;
        
    

【讨论】:

您是否搜索过嵌套或 caml 查询限制?可能会导致此代码出现问题。

以上是关于具有多个字段的嵌套 AND 和 OR 的 CAML 查询的主要内容,如果未能解决你的问题,请参考以下文章

具有自身 parentId 的实体框架核心嵌套对象

具有嵌套查询和 UUID 数组字段的 HQL/JPQL 查询

如何在存储为字符串的 bigquery 字段中取消嵌套多个数组?

如何设置映射输入的嵌套 JSON 数组对象的状态

多个嵌套集合字段和奏鸣曲类型集合

如何对 Solr 中的多个字段执行嵌套聚合?