查询 SharePoint OData 服务时在 LINQ 中使用日期比较

发布于 2024-12-01 11:22:17 字数 1057 浏览 2 评论 0原文

已解答:请在下面找到我对此问题的答案。

我正在尝试使用 LINQ 从 ASP.NET MVC 3 项目使用 SharePoint 2010 OData。我使用 ASP.NET MVC 3 项目模板和 Razor 视图引擎 (VS 2010) 创建了一个默认项目。我添加了指向我的 SharePoint 2010 网站的服务引用。

在我的 HomeController 的 Index 方法(这只是一个测试项目)中,我创建了一个变量来保存上下文,并将上下文变量的 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;

此查询忽略日期的时间部分。例如,如果 a.Begins 包含昨天的日期时间,则查询返回 AlertItem。另一方面,如果 a.Begins 包含具有当前日期(但时间更早)的日期时间,则比较返回 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;

我缺少什么?

ANSWERED: Go below to find my answer to this question.

I am trying to consume SharePoint 2010 OData from an ASP.NET MVC 3 project using LINQ. I created a default project using the ASP.NET MVC 3 project template with the Razor view engine (VS 2010). I added a service reference pointing to my SharePoint 2010 site.

In my HomeController's Index method (this is just a test project), I created a variable to hold the context and set the Credentials property of the context variable to the current default credentials.

A link query like the following works fine and I can use the created variable to access any of the data:

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

This query simply gets all of the announcements from a list called Alerts in the SharePoint site. This list has fields for the Title, Content, Beginning Date, and Expiration Date.

When I change the query to the following, I do not get the expected results:

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

This query ignores the time component of the date. For example, if a.Begins contains a datetime from yesterday, the query returns the AlertItem. If on the other hand, a.Begins contains a datetime with the current date (but an earlier time) the comparison returns false (and a.Begins == DateTime.Now returns true).

If I do the following, the second LINQ query works as expected:

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

What am I missing?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

逆蝶 2024-12-08 11:22:17

对于需要包含 DateTime 的时间元素的 Linq to SharePoint 查询,可以使用 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
                  ...

For a Linq to SharePoint query that needs to include the time element of the DateTime you can use 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
                  ...
策马西风 2024-12-08 11:22:17

我没有使用过SharePoint 2010的OData。但是,在针对 SharePoint 2010 对象模型进行查询时,您发布的异常是一种常见行为,回复:您必须先将查询转换为列表,然后才能查询数据。

这里的典型模式是:

var query = someSharePointQuery.ToList();

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

看起来很奇怪,但这就是 SP 2010 的工作原理。

I have not used SharePoint 2010's OData. However, when querying against the SharePoint 2010 object model, the anomaly you posted is a common behavior, re: you must convert the query to a list before you can query the data.

The typical pattern here is to:

var query = someSharePointQuery.ToList();

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

Seems odd, but this is how SP 2010 seems to work.

感情旳空白 2024-12-08 11:22:17

DateTime.Today 是否在某处被使用?我用 LinqPad 做了一些原型设计,复制结果的唯一方法是使用“where (a.Begins < DateTime.Today)”进行查询,

这是我对您所描述的内容所做的快速草图:

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;
    }
}

正如我所提到的,复制您所描述的结果的唯一方法是我将 where 子句中的 DateTime.Now 更改为 DateTime.Today 。我会检查您的代码是否意外使用了错误的 DateTime 方法。

顺便说一句,我强烈建议使用 LinqPad 来构建 Linq 查询的原型...它可以让您快速迭代代码并找出问题所在,从而节省您的时间。此外,它还非常值得花 50 美元购买智能感知和其他高级功能。

Is DateTime.Today getting used in there somewhere? I did some prototyping with LinqPad, and the only way to duplicate your results was if I had the query using "where (a.Begins < DateTime.Today)"

Here's the quick sketch I did of what it sounds like you're describing:

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;
    }
}

As I mentioned, the only way to duplicate your described results was if I changed DateTime.Now to DateTime.Today in the where clause. I would look through your code for accidental usages of the wrong DateTime method.

As an aside, I HIGHLY recommend using LinqPad for prototyping your Linq queries... It can save you time by allowing you to quickly iterate over your code and figure out what your trouble spots are. Also, it's very much worth the $50 for intellisense and other premium features.

你的呼吸 2024-12-08 11:22:17

在将来自许多不同来源的信息拼凑在一起后(没有一个来源涉及我遇到的问题的具体情况),我得出以下结论:

使用 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 数据服务连接到 SharePoint 时看到完全相同的行为,因此我只能假设 LINQ/WCF 数据服务在幕后生成相同的无效 CAML。

解决方案(假设我仍然想使用 LINQ/WCF 数据服务)是执行两个查询(如原始问题中所述)。第一个 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 语句将返回我最终感兴趣的所有项目;以及一些我不是的(因为它只比较日期时间的日期部分)。第二个 LINQ 语句将进一步将其精简为我感兴趣的内容。

After piecing together information from a lot of different sources -- none of which dealt with the exact circumstances of the problem that I am having, I've come to the following conclusion:

When querying SharePoint data using the SharePoint Object Model and Collaborative Application Markup Language (CAML), SharePoint by default does not use the time component of DateTime elements when doing comparisons. To tell SharePoint to use the time component, you must include the IncludeTimeValue = 'TRUE' property on the value type as shown here:

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

I found several blog posts that referenced a bug in LINQ to SharePoint that caused the generated CAML to be output as:

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

Notice that the IncludeTimeValue = 'TRUE' is on the FieldRef element instead of the Value element. Since this is not the right place for that property, it causes all LINQ to SharePoint queries that perform datetime comparisons to only compare on the date component.

Since I am seeing that exact same behavior when using LINQ and WCF Data Services to connect to SharePoint, I can only assume that under the covers LINQ/WCF Data Services is producing the same invalid CAML.

The solution (assuming I still want to use LINQ/WCF Data Services) is to perform two queries (as stated in the original question). The first LINQ query pulls the list data from SharePoint and stores it in a List. The second LINQ query handles the date comparisons to only pull the data I want.

Since in my particular circumstance, I may have many entries in the SharePoint list covering a large time span but will only be interested in entries on a particular day or couple of days, I wanted to find a way not to bring back the entire list in the first query.

What I settled on was doing a <= and >= comparison to get close, and then further limiting that in my second query. So my two queries now become:

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;

The first LINQ statement will return all the items that I am ultimately interested in; along with a few that I'm not (because it's comparing just the date component of the datetime). The second LINQ statement will further pare that down to just those that I'm interested in.

风月客 2024-12-08 11:22:17

我可以确认 SharePoint 2010 LINQ to SharePoint 未创建正确的 CAML(将 IncludeTimeValue='True' 添加到 FieldRef 而不是值)的错误已由 SharePoint Foundation 2010 的 2013 年 10 月累积更新修复。该修补程序可以从http://technet.microsoft.com/en-us/sharepoint/ff800847.aspx

SharePoint 2013 中也存在相同的错误,Microsoft 支持人员通知我应该在 2013 年 12 月的 SharePoint Foundation 2013 累积更新中修复该错误,但我无法确认这一点。我被告知该修复程序也已部署到 Office 365,但我无法确认这一点。

I can confirm the bug with SharePoint 2010 LINQ to SharePoint not creating the correct CAML (adding IncludeTimeValue='True' to the FieldRef instead of the Value) is fixed by the October 2013 Cumulative Update to SharePoint Foundation 2010. The hotfix can be downloaded from http://technet.microsoft.com/en-us/sharepoint/ff800847.aspx.

The same bug exists also in SharePoint 2013 which I was informed by Microsoft support should be fixed in the December 2013 Cumulative Update to SharePoint Foundation 2013, but I cannot confirm this. I was informed that the fix is also deployed to Office 365, but I cannot confirm this.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文