MongoDB .NET Driver:筛选查询中字符串转DateTime报错的解决方法
问题
我有一个MongoDB酒店预订集合,其中包含字段:
public string CreationDate { get; set; } // 其余字段已省略
我尝试检索两个日期范围内的酒店预订列表,单独执行日期转换逻辑正常,但在Filter、Where、Find查询中使用DateTime.ParseExact将CreationDate转为DateTime时均失败:
Filter方式代码
startDate = DateTime.ParseExact(Start + " " + "00:00:00", "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); // 此代码正常运行 endDate = DateTime.ParseExact(End + " " + "00:00:00", "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); // 此代码正常运行 var filter = Builders<HotelBookingDocument>.Filter.Gt(s => (DateTime.ParseExact(s.CreationDate + " " + "00:00:00", "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture)), startDate); filter &= Builders<HotelBookingDocument>.Filter.Lt(s => (DateTime.ParseExact(s.CreationDate + " " + "00:00:00", "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture)), endDate); return await HotelBookingCollection.Find(filter).ToListAsync(); // 此代码无法运行
Where方式代码
query = await HotelBookingCollection.AsQueryable().Where(s => ( DateTime.ParseExact(s.CreationDate + " " + "00:00:00", "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture) <= endDate) ).ToListAsync();
Find方式代码
query = await HotelBookingCollection.Find(s => ( startDate <= DateTime.ParseExact(s.CreationDate + " " + "00:00:00", "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture)) ).ToListAsync();
所有查询都会抛出如下错误:
System.InvalidOperationException: Unable to determine the serialization information for s => ParseExact(((s.CreationDate + " ") + "00:00:00"), "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture).
解决方法
方案1:修改实体类字段类型(推荐)
直接将CreationDate字段改为DateTime类型,MongoDB驱动可直接处理日期的序列化与反序列化,同时能利用日期索引提升查询性能,从根源避免字符串转日期的问题。
修改实体字段:
public DateTime CreationDate { get; set; }
查询代码简化为:
var filter = Builders<HotelBookingDocument>.Filter.Gte(s => s.CreationDate, startDate) & Builders<HotelBookingDocument>.Filter.Lte(s => s.CreationDate, endDate); var result = await HotelBookingCollection.Find(filter).ToListAsync();
方案2:转换查询日期为字符串格式匹配
若无法修改实体类,可将startDate和endDate转为与CreationDate一致的字符串格式(需确保日期字符串为yyyy-MM-dd这类字典序与时间顺序一致的格式),直接进行字符串范围查询。
示例代码:
// 假设CreationDate格式为"yyyy-MM-dd" string startDateStr = Start; // Start为传入的"yyyy-MM-dd"格式字符串 string endDateStr = End; var filter = Builders<HotelBookingDocument>.Filter.Gte(s => s.CreationDate, startDateStr) & Builders<HotelBookingDocument>.Filter.Lte(s => s.CreationDate, endDateStr); var result = await HotelBookingCollection.Find(filter).ToListAsync();
方案3:使用聚合管道在数据库层转换日期
利用MongoDB的$dateFromString操作符,在聚合管道中完成字符串到日期的转换,让驱动能正确解析查询逻辑。
示例代码:
var pipeline = new BsonDocument[] { new BsonDocument("$addFields", new BsonDocument( "convertedCreationDate", new BsonDocument( "$dateFromString", new BsonDocument { { "dateString", new BsonDocument("$concat", new BsonArray { "$CreationDate", "T00:00:00" }) }, { "format", "%Y-%m-%dT%H:%M:%S" } } ) )), new BsonDocument("$match", new BsonDocument( "$and", new BsonArray { new BsonDocument("convertedCreationDate", new BsonDocument("$gte", startDate)), new BsonDocument("convertedCreationDate", new BsonDocument("$lte", endDate)) } )) }; var result = await HotelBookingCollection.Aggregate<HotelBookingDocument>(pipeline).ToListAsync();
内容的提问来源于stack exchange,提问作者hanushi-thana
相关产品推荐
相关产品推荐

