使用嵌套AND和OR的CAML查询,针对多个字段进行查询

30
我正在编写一个概念验证代码,根据提供给我编写的高度特定的搜索Web服务的关键字动态生成基于CAML的查询。我没有在这个验证中使用SharePoint提供的搜索Web服务,因为我已经为我想要达到的目标使用了它。通过我的所有研究,我找不到一个类似的例子来实现我所尝试的目标,即检查多个字段的多个值。是的,我已经在SO上寻找了答案,包括这个: 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')
3个回答

57

由于不允许在一个条件组(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>

谢谢,Jason!我回来提供答案,因为我自己解决了这个问题。但是,我很高兴看到你的答案与我的结果相匹配,并非常感激你抽出时间帮助我和其他SO用户。 - Alban
感谢您的帖子。您提供的示例XML提供了一种很好的方法来检查嵌套语法。我使用它来想出生成等效于In运算符的方法。 - xr280xr

0
你可以尝试使用U2U查询构建器http://www.u2u.net/res/Tools/CamlQueryBuilder.aspx,你可以使用他们的API U2U.SharePoint.CAML.Server.dll和U2U.SharePoint.CAML.Client.dll。
我没有使用过它们,但我相信它们会帮助你完成任务。

14
除非你确定所发布的解决方案能够提供被请求的结果,否则不应在此处发布。使用U2U工具可节省时间,但你应该提供它生成的代码的有效示例。 - Mike T

0

这段代码将动态生成嵌套子句的表达式。我有一个情况,其中“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查询限制?这可能会对此代码造成问题。 - Phan Đức Bình

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接