Эквивалент SQL IN в CAML

Есть ли "хороший" способ создать запрос CAML для SharePoint, который делает что-то вроде этого?

SELECT *
FROM table
WHERE Id IN (3, 12, ...)

Или я застрял в кошмаре вложенных узлов <Or>?


EDIT: Это было мое решение для создания узлов <Or>.

/// Simulates a SQL 'Where In' clause in CAML
/// </summary>
/// <param name="columnType">Specifies the data type for the value contained by the field.</param>
/// <returns>Nested 'Or' elements portion of CAML query</returns>
public static string CamlIn<T>(string internalFieldName, string columnType, T[] values)
{
    XDocument doc = new XDocument();
    XElement prev = null;
    int index = 0;

    while (index < values.Length)
    {
        XElement element =
            new XElement("Or",
                new XElement("Eq",
                    new XElement("FieldRef",
                    new XAttribute("Name", internalFieldName)),
                new XElement("Value",
                    new XAttribute("Type", columnType),
                    values[index++].ToString())));

        if (index == values.Length - 1)
        {
            element.AddFirst(
                new XElement("Eq",
                    new XElement("FieldRef",
                    new XAttribute("Name", internalFieldName)),
                new XElement("Value",
                    new XAttribute("Type", columnType),
                    values[index++].ToString())));
        }

        if (prev != null)
            prev.AddFirst(element);
        else
            doc.Add(element);

        prev = element;
    }

    return doc.ToString(SaveOptions.DisableFormatting);
}

Использование:

int[] ids = new int[] { 1, 2, 4, 5 };
string query = string.Format("<Where>{0}</Where>", CamlIn("SomeColumn", "Number", ids));

Вывод:

<Where>
    <Or>
        <Or>
            <Or>
                <Eq>
                    <FieldRef Name=\"SomeColumn\" />
                    <Value Type=\"Number\">5</Value>
                </Eq>
                <Eq>
                    <FieldRef Name=\"SomeColumn\" />
                    <Value Type=\"Number\">4</Value>
                </Eq>
            </Or>
            <Eq>
                <FieldRef Name=\"SomeColumn\" />
                <Value Type=\"Number\">2</Value>
            </Eq>
        </Or>
        <Eq>
            <FieldRef Name=\"SomeColumn\" />
            <Value Type=\"Number\">1</Value>
        </Eq>
    </Or>
</Where>

Также сделана эта перегрузка для работы с полями поиска немного проще

/// <summary>
/// Simulates a SQL 'Where In' clause in CAML
/// </summary>
/// <param name="lookupId">Specify whether to use the Lookup column Id or Value.</param>
/// <returns>Nested 'Or' elements portion of CAML query</returns>
public static string CamlIn<T>(string internalFieldName, bool lookupId, T[] values)
{
    XDocument doc = new XDocument();
    XElement prev = null;
    int index = 0;

    while (index < values.Length)
    {
        XElement element =
            new XElement("Or",
                new XElement("Eq",
                    new XElement("FieldRef",
                        new XAttribute("Name", internalFieldName),
                        lookupId ? new XAttribute("LookupId", "TRUE") : null),
                    new XElement("Value",
                        new XAttribute("Type", "Lookup"),
                        values[index++].ToString())));

        if (index == values.Length - 1)
        {
            element.AddFirst(
                new XElement("Eq",
                    new XElement("FieldRef",
                        new XAttribute("Name", internalFieldName),
                        lookupId ? new XAttribute("LookupId", "TRUE") : null),
                    new XElement("Value",
                        new XAttribute("Type", "Lookup"),
                        values[index++].ToString())));
        }

        if (prev != null)
            prev.AddFirst(element);
        else
            doc.Add(element);

        prev = element;
    }

    if (values.Length == 1)
    {
        XElement newRoot = doc.Descendants("Eq").Single();
        doc.RemoveNodes();
        doc.Add(newRoot);
    }

    return doc.ToString(SaveOptions.DisableFormatting);
}

Ответ 2

Для пользователей, использующих Sharepoint 2010, доступен элемент IN:

http://msdn.microsoft.com/en-us/library/ff625761.aspx

Вот рабочий пример:

SPQuery locationsQuery = new SPQuery();
locationsQuery.Query = string.Concat("<Where>",
                                       "<In>",
                                         "<FieldRef Name='ID' />",
                                           "<Values>",
                                             "<Value Type='Number'>6</Value>",
                                             "<Value Type='Number'>7</Value>",
                                             "<Value Type='Number'>8</Value>",
                                           "</Values>",
                                       "</In>",
                                     "</Where>");

Ответ 3

FullTextSqlQuery

Для поиска MOSS можно использовать операторы SQL, используя класс FullTextSqlQuery. У меня нет опыта использования этого класса лично. Эти статьи могут быть полезны:

YACAMLQT

Кроме того, есть также YACAMLQT (еще один инструмент запросов CAML), который позволяет создавать запросы CAML SharePoint с использованием синтаксиса T-SQL.

LINQ to SharePoint

Если вы знакомы с LINQ, то проект LINQ to SharePoint предоставляет инструмент для запроса списков SharePoint с использованием синтаксиса LINQ. Обратите внимание, что этот инструмент все еще находится на стадии альфа-тестирования, поэтому он может быть не готов к работе.

U2U CAML Query Builder

Если вы работаете с запросами CAML, я бы порекомендовал использовать инструмент U2U CAML Query Builder для SharePoint (2003 и 2007) для создания ваших запросов CAML. Этот инструмент позволяет создать строку запроса и выполнить ее для целевого списка, используя интерфейс "укажи и щелкни", как показано ниже.

U2U CAML Query Builder for SharePoint in action
(источник: u2u.net)

Из вышеперечисленных четырех методов я могу порекомендовать U2U CAML Query Builder, используя его почти ежедневно в течение последних 6 месяцев. Он также является наиболее широко используемым инструментом CAML в сообществе SharePoint.

Обратите внимание: если вы строите запросы CAML в коде, я рекомендую вам взглянуть на проект CAML.NET на CodePlex, который предоставляет "набор инструментов на основе языка .NET для создания динамических, многократно используемых компонентов запросов CAML".,

Ответ 4

Я столкнулся с подобной вещью и в конечном итоге должен был создать рекурсивный алгоритм для генерации вложенной структуры OR. Вот мой алгоритм

var DynamicQuery = '<Query><Where>{{DYNAMICSTRING}}</Where></Query>';
var OneOR = '<Or><Eq><FieldRef Name="IMEI" /><Value Type="Text">{{SearchValue}}</Value></Eq>{{DYNAMICSTRING}}</Or>';
var TwoOr = '<Or><Eq><FieldRef Name="IMEI" /><Value Type="Text">{{SearchValue}}</Value></Eq><Eq><FieldRef Name="IMEI" /><Value Type="Text">{{SearchValue}}</Value></Eq></Or>';
var OnlyEq =  '<Eq><FieldRef Name="IMEI" /><Value Type="Text">{{SearchValue}}</Value></Eq>';
function generateAdvancedInQuery(x){
    if(x.length == 1)
        return OnlyEq.replace('{{SearchValue}}',x[0]);
    else if(x.length == 2)
        return TwoOr.replace('{{SearchValue}}',x[0]).replace('{{SearchValue}}',x[1]);
    else 
        return OneOR.replace('{{SearchValue}}',x[x.length-1]).replace('{{DYNAMICSTRING}}',generateAdvancedInQuery(x.splice(0,x.length-1) ) );   
}

x = ['438753234098792','438753234098793','438753234098794','438753234098795','438753234098796','438753234098797','438753234098798'];

var Caml = DynamicQuery.replace('{{DYNAMICSTRING}}',generateAdvancedInQuery(x) )

Это генерирует XML-запрос caml как

<Query>
    <Where>
        <Or>
            <Eq>
                <FieldRef Name="IMEI" />
                <Value Type="Text">438753234098798</Value>
            </Eq>
            <Or>
                <Eq>
                    <FieldRef Name="IMEI" />
                    <Value Type="Text">438753234098797</Value>
                </Eq>
                <Or>
                    <Eq>
                        <FieldRef Name="IMEI" />
                        <Value Type="Text">438753234098796</Value>
                    </Eq>
                    <Or>
                        <Eq>
                            <FieldRef Name="IMEI" />
                            <Value Type="Text">438753234098795</Value>
                        </Eq>
                        <Or>
                            <Eq>
                                <FieldRef Name="IMEI" />
                                <Value Type="Text">438753234098794</Value>
                            </Eq>
                            <Or>
                                <Eq>
                                    <FieldRef Name="IMEI" />
                                    <Value Type="Text">438753234098792</Value>
                                </Eq>
                                <Eq>
                                    <FieldRef Name="IMEI" />
                                    <Value Type="Text">438753234098793</Value>
                                </Eq>
                            </Or>
                        </Or>
                    </Or>
                </Or>
            </Or>
        </Or>
    </Where>
</Query>