C# - 如何在MongoDB中使用DateTimeOffset

19
public class ScheduledEvent : Event
{
    public DateTimeOffset StartDateTime { get; set; }
}

StartDateTime = 5/27/2013 2:09:00 AM +00:00 表示 05/26/2013 07:09 PM PST。

MongoDB中记录的内容为:

db.ScheduledEvent.find().toArray()[
    {
        "_id": BinData(3, "ZE2p31dh00qb6kglsgHgAA=="),
        "Title": "Today 26th at 7:09pm",
        "Length": "00:00:00",
        "MoreInformation": "http://1.com",
        "Speakers": [{
            "_id": BinData(3, "ndzESsQGukmYGmMgKK0EqQ=="),
            "Name": "Mathias Brandewinder"
            }
        ],
        "Location": {
            "_id": BinData(3, "AAAAAAAAAAAAAAAAAAAAAA=="),
            "Name": "Somwhere "
        },
        "Organizers": [{
            "_id": BinData(3, "AAAAAAAAAAAAAAAAAAAAAA=="),
            "Name": null
        }],
        "CreatedOn": [
            NumberLong("635052144104050898"),
            0
        ],
        "StartDateTime": [
            NumberLong("635052173400000000"),
            0
        ]
    }
]

我意识到在MongoDB中StartDateTime被存储为Ticks。


var dateMarker = DateTimeOffset.UtcNow;
var nextDay = dateMarker.AddDays(1);

这个查询不起作用:

var today = EventRepoistory
    .All()
    .Where(z => z.StartDateTime >= dateMarker 
        && z.StartDateTime < nextDay)
    .OrderByDescending(z => z.StartDateTime)
    .ToList();

我已经在Mongo C#驱动程序中添加了一个查询显示器,显示以下查询:

{ "$query" : { "StartDateTime" : { "$gte" : [NumberLong("635052168609734070"), 0], "$lt" : [NumberLong("635053032609734070"), 0] } }, "$orderby" : { "StartDateTime" : -1 } }

下限 = 6350521 68609734070

服务器 = 6350521 73400000000

上限 = 6350530 32609734070

问题: 为什么这个 MongoDB 查询不返回任何结果?

db.ScheduledEvent.find({
  "$query": {
    "StartDateTime": {
      "$gte": [NumberLong("635052168609734070"), 0],
      "$lt": [NumberLong("635053032609734070"), 0]
    }
  },
  "$orderby": {
    "StartDateTime": -1
  }
})

我研究了这个话题,发现了这个解决方案:MongoDB和DateTimeOffset类型

但是LINQ提供程序是否正在执行其应该执行的操作?


我还尝试过以下代码:

db.ScheduledEvent.find({
  "StartDateTime": {
    "$gte": [NumberLong("1"), 0]
  }
})

但它没有返回任何结果。


嗨,你有找到问题的根本原因吗?我也有同样的问题... - soupy1976
我在发现这个问题后暂停了我的项目。但我还没有回来继续它。 - Petar Vučetin
3个回答

8
正如其他答案所述,问题的根本原因在于默认情况下将DateTimeOffset字段序列化为数组(带有刻度和偏移量)。
如果能够在数据访问层中本地化更改并使用特定于MongoDB的查询,则dsandor提出的解决方案可以很好地工作。
但是,如果您的存储库公开了IQueryable<ScheduledEvent>,并且某些LINQ查询应用于服务层,则这种方法不起作用。
更通用的方法是更改DateTimeOffset字段序列化到MongoDB的方式,以便LINQ查询正确运行,无需自定义MongoDB查询即可正常运行。
您可以使用BsonRepresentation(BsonType.String)属性轻松更改DateTimeOffset字段的序列化。
public class ScheduledEvent : Event
{
    [BsonRepresentation(BsonType.String)]
    public DateTimeOffset StartDateTime { get; set; }
}

在这种情况下,DateTimeOffset字段以字符串形式保存在MongoDB中,格式为2020-04-03T08:12:23+03:00,并且LINQ查询正常工作。

1
你还可以使用BsonType.DateTime,它会有效地将其存储为UTC时间。 - Rob

7
这里有一个类似的答案:MongoDB和DateTimeOffset类型 (就像你在问题中提到的)。
我通过以下方式使用C#驱动程序成功地实现了它:
var query = Query.GT("StartDateTime.0", startDate.Ticks);
var json = query.ToJson();

生成以下JSON:

{ "StartDateTime.0" : { "$gt" : NumberLong("635251617859913739") } }

上述JSON有效。根据链接的答案,原因是DateTimeOffset是一个数组。

当我使用LINQ时,我得到了(正如您所指出的)不同的JSON结果。

var query = from r in col.AsQueryable<MyObjectType>()
    where r.StartDateTime>= startDate && r.StartDateTime< endDate
    select r;

上面的LINQ查询生成以下JSON:
{ "StartDateTime" : { "$gte" : [NumberLong("635251617859913739"), 0], "$lt" : [NumberLong("635251635859913739"), 0] } }

我不确定C#驱动程序中的LINQ提供程序是否需要修复以处理DateTimeOffset,但使用查询构建器指定DateTimeOffset数组的第一个元素(StartDateTime.0)是我使其工作的唯一方法。


1
看起来一年后情况仍然存在。不得不做同样的事情。 - Sergio Rykov

2

在查询中使用以下语法:

{
    "StartDateTime.0": {
        "$gte": 635052168609734070
    }
}

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