I'm working with MongoDB, and found weird behaviour (at least for me). I got time difference when inserting from C# and retrieve it from MongoDB.
My entity :
[BsonId]
public ObjectId Id { get; set; }
public bool IsActive { get; set; }
public string CreatedBy { get; set; }
public DateTime CreatedTime { get; set; }
public string Name { get; set; }
Timestamp was inserted using below code :
public bool Insert(AccountCategories _input)
{
_input = new AccountCategories();
_input.CreatedBy = "super-admin";
_input.CreatedTime = DateTime.Now;
_input.Id = new ObjectId();
_input.IsActive = true;
_input.Name = "test-name";
var _result = _repo.Insert(_input);
return _result;
}
Inserted data : {4/30/16 9:04:36 PM}
Retrieval data : {4/30/16 2:04:36 PM}
I have tried to modify the entities by adding Bson attribute, but it was not working:
[BsonRepresentation(BsonType.Document)]
public DateTime CreatedTime { get; set; }
Why this behaviour happened ? and how can I fix this ?
I managed to found the answer after changing my keyword during search on this site and google.
According to MongoDB manual :
https://docs.mongodb.org/manual/tutorial/model-time-data/
Time is defaulted to UTC, that's why I got 7 hours difference (my bad to not look into the manual first)
So I managed to fix my problem by adding BsonAttribute to the Datetime as below :
[BsonDateTimeOptions(Kind=DateTimeKind.Local)]
public DateTime CreatedTime { get; set; }
source : Dealing with how MongoDB stores DateTime when used with Service Locator Pattern
Related
I have a data model, with the help of EF migration I created a data table based on this model.
public class Event
{
public int Id { get; set; }
public string Theme { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public string Place { get; set; } = string.Empty;
}
After that, I remembered that I forgot to add the date and time field. I added this field and created a new migration, after which I applied the update database command.
public class Event
{
public int Id { get; set; }
public string Theme { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public DateTime EventTime { get; set; }
public string Place { get; set; } = string.Empty;
}
When executing my request to update the date and time via the Web Api, I get the following error:
Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details. ---> System.InvalidCastException: Cannot write DateTime with Kind=Unspecified to PostgreSQL type 'timestamp with time zone', only UTC is supported. Note that it's not possible to mix DateTimes with different Kinds in an array/range. See the Npgsql.EnableLegacyTimestampBehavior AppContext switch to enable legacy behavior.
When executing my request to update the date and time via the Web Api, I get the following error. Before adding the date and time field, everything worked fine, with MSSQL everything also works fine and the date is added well.
Cannot write DateTime with Kind=Unspecified to PostgreSQL type 'timestamp with time zone', only UTC is supported
That means you need to convert your EventTime to UTC
I have an Entity MVC app with a code-first database. I need to produce a search box to search between 2 dates and return the records between those dates.
I will call the method with jQuery/ajax and render the results in a table.
I've tried writing an API, with no success. I am not even sure if this is the correct way to go about it?
namespace Areometrex_Leaflet.Models
{
[Table ("Flight_Lines")]
public class Flight_line
{
[Key]
public string Swath_name { get; set; }
public string Flight_name { get; set; }
public string Swath_record { get; set; }
public string Flight_date { get; set; }
public decimal Start_lat { get; set; }
public decimal Start_long { get; set; }
public decimal End_lat { get; set; }
public decimal End_long { get; set; }
public decimal Altitude { get; set; }
public DateTime Time_start { get; set; }
public DateTime Time_end { get; set; }
public string Sensor { get; set; }
}
public class FlightLineContext : DbContext
{
public DbSet<Flight_line> Flight_Lines { get; set; }
}
}
This is my model that holds the objects in the database. I need to search the "Flight_date" property, that is held in my DB in this following format as an "nvarchar" :
17/11/2018 11:09:18 PM
My current API looks something like this:
[HttpPost]
public IEnumerable<Flight_line> SearchFlight_Line()
{
string start, end;
var rc = RequestContext;
var data = rc.Url.Request.GetQueryNameValuePairs();
{
start = data.FirstOrDefault().Value ?? string.Empty;
end = data.LastOrDefault().Value ?? string.Empty;
}
//db format: 17/11/2018 11:22:56 PM
var s = DateTime.Parse(start);
var flightSearch = new List<Flight_line>();
using (_context)
{
var sql = $"SELECT * FROM Flight_Lines WHERE Flight_Date BETWEEN '{start}' AND '{end}'";
flightSearch = _context.Flight_Lines.SqlQuery(sql).ToList<Flight_line>();
}
return flightSearch;
}
Ideally, I want to call this API with jquery/Ajax and return results to be displayed in an MVC view. My guess is that this is dead easy, but I am only learning and I'm running out of ideas. I would have thought this was really simple, but I am struggling to find the answers I am looking for online, which leads me to believe perhaps I am doing it wrong?
First of all, don't save dates as string in your database, you will just have problems later on.
Instead of:
public string Flight_date { get; set; }
Set it up as DateTime:
public DateTime Flight_date { get; set; }
As far as the query for searching flights go, you can try this. This will return a list of "Flight_line" objects which you can then return wherever you need.
DateTime start = DateTime.Now;
DateTime end = DateTime.Now.AddDays(7);
var flights = _context.Flight_line.Where(f => f.Flight_date >= start && f.Flight_date <= end).ToList();
I have the following document called Attendances
{
"_id" : ObjectId("5a4ffb00762caf6b54f61ebb"),
"AttnDate" : ISODate("2018-01-05T22:24:00.490Z"),
"AllAttendances" : [
{
"FullName" : "DOMAIN\Zack",
"Logged" : ISODate("2018-01-05T22:23:46.835Z"),
"Pauses" : [
{
PauseStartAt: ISODate("2018-01-05T22:30:46.835Z"),
PauseEndAt: ISODate("2018-01-05T22:35:46.835Z")
}
]
}
]
}
How can i add new items to Pauses. This is my attempt but i have this error "Cannot convert lambda expression to type 'fielddefinition because it is not a delegate type.
My attempt
var filter = Builders<Attendance>.Filter.Eq(a => a.Id, currentAttn.Id) & Builders<Attendance>.Filter.ElemMatch(s => s.AllAttendances, Builders<TimeRecord>.Filter.Eq(n => n.FullName, userName));
var update = Builders<Attendance>.Update.Push(e => e.AllAttendances[-1].Pauses, pauses);
context.Attendances.FindOneAndUpdate(filter, update);
I followed this guide
Attendance Class
public class Attendance
{
[JsonConverter(typeof(ObjectIdConverter))]
public ObjectId Id { get; set; }
[BsonDateTimeOptions(Kind = DateTimeKind.Local)]
public DateTime AttnDate { get; set; }
public List<TimeRecord> AllAttendances { get; set; }
}
TimeRecord Class (AllAttendances)
public class TimeRecord
{
public string FullName { get; set; }
[BsonDateTimeOptions(Kind = DateTimeKind.Local)]
public DateTime Logged { get; set; }
public List<Pause> Pauses { get; set; }
}
Pause Class
public class Pause
{
[BsonDateTimeOptions(Kind = DateTimeKind.Local)]
public DateTime PauseStartedAt { get; set; }
[BsonDateTimeOptions(Kind = DateTimeKind.Local)]
public DateTime PauseEndedAt { get; set; }
}
You need to update your filter to
var filter = Builders<Attendance>.Filter.Eq(a => a.Id, id) &
Builders<Attendance>.Filter.ElemMatch(s => s.AllAttendances, x => x.FullName == userName);
The first argument of ElemMatch is the field, the second argument is the filter.
Looking at it from a different angle, I would suggest you don't use ObjectIDs in c#. I always define ObjectIds as strings in my models and use the Bson attribute decorators to define them as ObjectId's in the database
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
Purely for the pain it causes trying to use ObjectIds in C#. Strings are much easier to handle. Your document in mongodb will still look the same, and you will not need to cast as object id's in your code at all:
_id : ObjectId("xxxxxxx")
This should help you get around the issue of the compiler not knowing how to do the conversion
I have one class.
I adding class to mongodb.
but DateTime Properties as shows the string
c#
public class FRM_FORMREQUEST
{
public int ORACLE_ID { get; set; }
public string FORMNUMBER { get; set; }
public string COMPANYCODE { get; set; }
public DateTime? RECORDDATE { get; set; }
public string RECORDUSER { get; set; }
}
mongodb record
{
"_id" : ObjectId("56927dfc249d951f1031f526"),
"ORACLE_ID" : 771653,
"FORMNUMBER" : "4992014309217",
"COMPANYCODE" : "499",
"RECORDDATE" : "2014-08-21T19:35:27",
"RECORDUSER" : "parttime35"
}
Business
var jsonData = Newtonsoft.Json.JsonConvert.SerializeObject(FRM_FORMREQUEST);
MongoDB.Bson.BsonDocument document = MongoDB.Bson.Serialization.BsonSerializer.Deserialize<BsonDocument>(jsonData);
frmFormCollection.Insert(document);
I want insert like Date
thanks for all help.
The problem is that you're serializing it to JSON using Json.Net, which will write the dates as strings in the ISO 8601 standard format by default. Then you're de-serializing it to a BsonDocument using the BsonSerializer, which (unless you give it any other instructions) will just assume those are strings.
I have to ask, why jump through these hoops? Why not just let the driver serialize your object for you when you call Insert()?
collection.Insert(FRM_FORMREQUEST);
Or, if you have to work with a BsonDocument, use the mongo BsonSerializer to convert your object directly (instead of converting it to Json first).
var document = FRM_FORMREQUEST.ToBson();
collection.Insert(document);
I'm using c# driver to interact with mongoDB.
I have a class that I created and which I populate with the data I get from mongoDB.
One of the properties in that class is DateTime.
The value I get from mongo is /\Date(number)/. Which is ok because this is what I'm suppose to return to the client.
The value that I get from mongo after I retrieve the data is ISODate(some number).
I get an exception: "Invalid JSON primitive: ISODate".
How can I configure mongoDB to save the DateTime like I got it i.e. /\Date(number)/?
Sorry L.B - I didn't noticed your answer but went straight to the answer I was given.
Here's the class I'm trying to deserialize:
public class EventDate
{
public EventDate()
{
}
public int? VenueConfigID { get; set; }
public string Category { get; set; }
public DateTime DateAndTime { get; set; }
public string DisplayDate { get; set; }
public string StartDate { get; set; }
public string EndDate { get; set; }
public string ShortNote { get; set; }
public string Home { get; set; }
public int? ID { get; set; }
public string Name { get; set; }
}
Here's how I deserialize it:
mongo = MongoServer.Create();
mongo.Connect();
db = mongo.GetDatabase("productionDB");
var col = db.GetCollection<BsonDocument>("eventDates");
var query = Query<PerformerDates>.EQ(ev => ev.PerformerID, performerId);
//MongoCursor<BsonDocument> performer = col.Find(query);
MongoCursor<BsonDocument> performer = col.FindAll();
JavaScriptSerializer js = new JavaScriptSerializer();
List<EventDate> finalMatchedDates = new List<EventDate>();
foreach (var p in performer)
{
//System.Threading.Tasks.Task<EventDate[]> obj2 = JsonConvert.DeserializeObjectAsync<EventDate[]>(p.Elements.ToList()[3].Value.ToString());
EventDate[] obj3 = JsonConvert.DeserializeObject<EventDate[]>(p.Elements.ToList()[3].Value.ToString());
}
mongo.Disconnect();
Solved!!
Eventually I solved it. I used a string instead of a DateTime. When I get it from the DB, I convert it to a DateTime and when I sent it back to the client I serialize it with the format of: /\Date()/
Just use BsonSerializer.Deserialize method.
MongoDB's serializer has a much higher performance over NewtonSoft's Json.Net or Microsoft's DataContractSerializer.
Very common occurring problem! One solution is to use JSON.NET.
See this answer for more help. Although you might be confused with JSON DateTime object but don't worry. It will work!
string json; // Assign JSON here.
var v = Newtonsoft.Json.JsonConvert.DeserializeObjectAsync<T>(json);