【问题标题】:CAML query with nested ANDs and ORs for multiple fields具有多个字段的嵌套 AND 和 OR 的 CAML 查询
【发布时间】: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')

【问题讨论】:

    标签: sharepoint caml nested-query


    【解决方案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>{{FirstExpression}}{{SecondExpression}}</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>{{FirstExpression}}{{SecondExpression}}</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 查询限制?可能会导致此代码出现问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-27
    • 1970-01-01
    • 2013-02-06
    相关资源
    最近更新 更多