Использование сравнения дат в LINQ при запросе службы OData SharePoint - PullRequest
2 голосов
/ 26 августа 2011

ОТВЕТ: перейдите ниже, чтобы найти ответ на этот вопрос.

Я пытаюсь использовать OData для SharePoint 2010 из проекта ASP.NET MVC 3 с использованием LINQ.Я создал проект по умолчанию, используя шаблон проекта ASP.NET MVC 3 с механизмом представления Razor (VS 2010).Я добавил ссылку на службу, указывающую на мой сайт SharePoint 2010.

В методе Index моего HomeController (это всего лишь тестовый проект) я создал переменную для хранения контекста и установил для свойства Credentials этой переменной значениетекущие учетные данные по умолчанию.

Запрос ссылки, подобный следующему, прекрасно работает, и я могу использовать созданную переменную для доступа к любым данным:

var query = from a in context.Alerts
            select a;

Этот запрос просто получает все объявленияиз списка под названием Оповещения на сайте SharePoint.В этом списке есть поля для заголовка, содержимого, даты начала и срока действия.

Когда я изменяю запрос на следующий, я не получаю ожидаемых результатов:

var query = from a in context.Alerts
            where (a.Begins < DateTime.Now)
            select a;

Thisзапрос игнорирует компонент времени даты.Например, если a.Begins содержит дату и время со вчерашнего дня, запрос возвращает AlertItem.Если, с другой стороны, a.Begins содержит datetime с текущей датой (но более ранним), сравнение возвращает false (а a.Begins == DateTime.Now возвращает true).

Если я сделаюдалее второй запрос LINQ работает как положено:

var query = (from a in context.Alerts
            select a).ToList();
var query2 = from q in query
             where (q.Begins < DateTime.Now)
             select q;

Чего мне не хватает?

Ответы [ 5 ]

2 голосов
/ 02 марта 2016

Для запроса Linq to SharePoint, который должен включать элемент времени DateTime, вы можете использовать TimeOfDay.

var next_slots = (from s in dc.HRDates
                  where
                  s.StartTime.HasValue &&
                  s.StartTime.Value.Date == appt.Value.Date &&
                  s.StartTime.Value.TimeOfDay == appt.Value.TimeOfDay
                  ...
1 голос
/ 29 августа 2011

Я не использовал OData в SharePoint 2010. Однако при выполнении запросов к объектной модели SharePoint 2010 опубликованная вами аномалия является обычным явлением, повторяйте: вы должны преобразовать запрос в список, прежде чем сможете запрашивать данные.

Типичная схема здесь:

var query = someSharePointQuery.ToList();

var results = query.Where(...).First(...);

Кажется странным, но так выглядит SP 2010.

0 голосов
/ 31 января 2014

Я могу подтвердить, что в SharePoint 2010 LINQ to SharePoint не удалось создать правильный CAML (добавление IncludeTimeValue = 'True' в FieldRef вместо значения) исправлено накопительным обновлением для SharePoint Foundation 2010 за октябрь 2013 г. Исправление можетбыть загруженным из http://technet.microsoft.com/en-us/sharepoint/ff800847.aspx.

Такая же ошибка существует и в SharePoint 2013, о которой мне сообщили, что служба поддержки Microsoft должна быть исправлена ​​в накопительном обновлении SharePoint Foundation 2013 в декабре 2013 года, но я не могу подтвердить это.Мне сообщили, что исправление также развернуто в Office 365, но я не могу подтвердить это.

0 голосов
/ 29 августа 2011

После объединения информации из множества разных источников - ни один из которых не касался точных обстоятельств моей проблемы, я пришел к следующему выводу:

При запросе данных SharePoint с использованием объектной модели SharePoint и языка разметки приложений (CAML) SharePoint по умолчанию не использует компонент времени элементов DateTime при выполнении сравнений. Чтобы указать SharePoint использовать компонент времени, необходимо включить свойство IncludeTimeValue = 'TRUE' в тип значения, как показано здесь:

<Where>
 <Eq>
  <FieldRef Name='Begins' />
  <Value Type='DateTime'  IncludeTimeValue='TRUE'>
   2008-03-24T12:00:00Z
  </Value>
 </Eq>
</Where>

Я нашел несколько сообщений в блоге, в которых упоминалась ошибка в LINQ to SharePoint, из-за которой сгенерированный CAML выводился в виде:

<Where>
 <Eq>
  <FieldRef Name='dateTimeField'  IncludeTimeValue='TRUE' />
  <Value Type='DateTime'>
   2008-03-24T12:00:00Z
  </Value>
 </Eq>
</Where>

Обратите внимание, что IncludeTimeValue = 'TRUE' находится в элементе FieldRef вместо элемента Value. Поскольку это не подходящее место для этого свойства, все запросы LINQ to SharePoint, которые выполняют сравнения по времени и дате, сравниваются только с компонентом даты.

Поскольку я вижу такое же поведение при использовании LINQ и WCF Data Services для подключения к SharePoint, я могу только предположить, что под прикрытием LINQ / WCF Data Services выдает тот же недопустимый CAML.

Решение (при условии, что я все еще хочу использовать LINQ / WCF Data Services) состоит в том, чтобы выполнить два запроса (как указано в исходном вопросе). Первый запрос LINQ извлекает данные списка из SharePoint и сохраняет их в списке. Второй запрос LINQ обрабатывает сравнения дат, чтобы получить только те данные, которые мне нужны.

Поскольку в моих конкретных обстоятельствах у меня может быть много записей в списке SharePoint, охватывающих большой промежуток времени, но меня будут интересовать записи только в определенный день или пару дней, я хотел найти способ не возвращать весь список в первом запросе.

Я остановился на сравнении <= и> =, чтобы приблизиться, а затем еще больше ограничил это во втором запросе. Итак, два моих запроса теперь стали:

DateTime RightNow = DateTime.Now;
var query = (from a in context.Alerts
             where (a.Begins <= RightNow) && (a.Expires >= RightNow)
             select a).ToList();
var query2 = from q in query
             where q.Begins < RightNow) && (a.Expires > RightNow)
             select q;

Первое выражение LINQ вернет все элементы, которые меня в конечном итоге интересуют; наряду с некоторыми, что я не (потому что он сравнивает только компонент даты datetime). Второе утверждение LINQ еще больше урежет это до тех, которые меня интересуют.

0 голосов
/ 26 августа 2011

DateTime.Today где-то привыкнет? Я сделал несколько прототипов с LinqPad, и единственный способ дублировать ваши результаты был, если бы у меня был запрос с использованием «where (a.Begins

Вот быстрый набросок, который я сделал для того, что звучит так, как вы описываете:

void Main()
{
    List<Alerts> alerts = new List<Alerts>();
    alerts.Add(new Alerts(DateTime.Now.AddDays(-1)));
    alerts.Add(new Alerts(DateTime.Now));

    var query = from a in alerts
                where (a.Begins < DateTime.Now)
                select a;
    foreach (var element in query)
    {
        Console.WriteLine(element.Begins);
    }

}
public class Alerts
{
    public DateTime Begins {get; set;}
    public Alerts(DateTime begins)
    {
        Begins = begins;
    }
}

Как я уже упоминал, единственный способ дублировать описанные вами результаты был, если я изменил DateTime.Now на DateTime.Today в предложении where. Я бы посмотрел ваш код на случайное использование неправильного метода DateTime.

Кроме того, я НАСТОЯТЕЛЬНО рекомендую использовать LinqPad для создания прототипов ваших запросов Linq ... Это может сэкономить ваше время, позволяя вам быстро перебирать ваш код и выяснять, в чем заключаются ваши проблемы. Кроме того, он стоит 50 долларов за intellisense и другие премиальные функции.

...