I have this Bson model in mongodb:
"setting|resources" : {
"Name" : "EsupHamrah",
"Id" : "449ea0e1-0261-4bee-b096-a838746c94ea",
"Children" : [..
I have created this contract model :
public class SettingResources
{
public string Name { get; set; }
[BsonElement]
//[BsonRepresentation(BsonType.String)]
public string Id { get; set; }
//[BsonId(IdGenerator = typeof(CombGuidGenerator))]
//public string Id { get; set; }
public IList<object> Children { get; set; }
}
When i do query I got tthis error:
An error occurred while deserializing the configs property of class ConsoleMongoApp.Applications: An error occurred while deserializing the values property of class ConsoleMongoApp.Configs: An error occurred while deserializing the resources property of class ConsoleMongoApp.Values: Element 'Id' does not match any field or property of class ConsoleMongoApp.SettingResources.
The Id is just string, not GUID or ObjectId but why mongo can not do map the id?
your model in mongodb is wrong, there is a | (pipe) in Json string, try fix it on "settingResources":
"settingResources" : {
"Name" : "EsupHamrah",
"Id" : "449ea0e1-0261-4bee-b096-a838746c94ea",
"Children" : [..
Related
I am trying to retrieve data from local MongoDb with JSON documents like this:
{
"teryt_num_code" : "AB",
"id": 1,
"name": "Alabama"
}
I have created a POCO class as following:
public class Sensor
{
public int id { get; set; }
public string name { get; set; }
public string teryt_num_code { get; set; }
}
To retrieve all data from my database I use a method below:
public async Task<ICollection<Sensor>> GetAllAsync() => await _collection.Find(_ => true).ToListAsync();
but the exception was thrown calling that method:
An error occurred while deserializing the property of class Sensor:
Element 'id' does not match any field or property of class Sensor.
What I am doing wrong?
By default, the id property of your class is mapped to the BSON id (property _id on the document). This leaves the id property in the MongoDB document without a corresponding property in the POCO. Therefore, the error is raised.
In order to fix the deserialization error, you can apply both a BsonNoId and a BsonIgnoreExtraElements attribute to the POCO:
[BsonNoId]
[BsonIgnoreExtraElements]
public class Sensor
{
public int id { get; set; }
public string name { get; set; }
public string teryt_num_code { get; set; }
}
BsonNoId disables the convention; therefore BSON id is mapped to POCO id. BsonIgnoreExtraElements fixes the error that the driver does not know how to deserialize the _id property that every MongoDB document contains.
I'm having big problems when I'm overriding the Id property in a derived class in my MongoDB storage setup.
The base class that all of my data models inherit looks like this:
public abstract class DataModel
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public virtual string Id { get; set; }
public DateTime Created { get; set; }
public DateTime Modified { get; set; }
public DateTime Deleted { get; set; }
}
Then there are a few particular child data models that use upserts. This requires me to annotate the overridden Id property with [BsonIgnoreIfDefault] as per this answer:
public class ChildDataModel : DataModel
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
[BsonIgnoreIfDefault] // <---- need this for Upserts to work
public override string Id { get; set; }
... // child-specific properties
}
But unfortunately it results in this error:
The property 'Id' of type
'Namespace.ChildDataModel' cannot
use element name '_id' because it is already being used by property
'Id' of type 'Namespace.DataModel'.
I've tried registering class maps, adding a type discriminator with RootClass = true on the base model, as well as defining my child data models on the base class with the special [BsonKnownTypes(typeof(ChildDataModel), ...)] attribute, but to no avail.
What am I doing wrong here?
MongoDB driver by convention tries to map all the properties named Id into _id in class map. As you have two classes it registers the _id twice. What's more BsonIgnoreIfDefault would work fine if the Id was null but here it's not since the driver automatically will generate the value when you insert new document.
To fix that you can use BsonIgnore if you want to have single _id in MongoDB
public class ChildDataModel : DataModel
{
[BsonRepresentation(BsonType.ObjectId)]
[BsonIgnore]
public override string Id { get; set; }
}
will be stored as:
{
"_id" : ObjectId("5cb5fe72e2a22b3848b6a1f6"),
"Created" : ISODate("2019-04-16T16:10:25.908Z"),
"Modified" : ISODate("2019-04-16T16:10:25.914Z"),
"Deleted" : ISODate("2019-04-16T16:10:25.914Z")
}
or you can use BsonNoId attribute if you want to have two values stored separately:
[BsonNoId]
public class ChildDataModel : DataModel
{
[BsonRepresentation(BsonType.ObjectId)]
public override string Id { get; set; }
}
will be:
{
"_id" : ObjectId("5cb5fecde2a22b3088ef731c"),
"Created" : ISODate("2019-04-16T16:11:56.810Z"),
"Modified" : ISODate("2019-04-16T16:11:56.822Z"),
"Deleted" : ISODate("2019-04-16T16:11:56.822Z"),
"Id" : ObjectId("5cb5fecde2a22b3088ef731c")
}
however it's still the same value from application point of view
i want to implement a class that one of the attribute is dynamic but i can't seem to figure out how to do that...
public class myClass
{
public datetime timeStamp { get; set; }
public object variable { get; set; }
public string name { get; set; }
}
I need to read a archive that has the type of the "variable" inside as a integer, for example
This is just an exaple of a json or something that i will use, the "variable" attribute of the clas (in this example) will be a string, but there are sometimes that this attribute should be a integer(example2)
Ex1:
{"name" : "Variable1" , "variable" : "string" : "myString" , "timeStamp" : "852852852" }
Ex2:
{"name" : "Variable2" , "variable" : "int32" : "125125" , "timeStamp" : "852852852" }
You could make OPC_UA a generic class:
class OPC_UA<T>
{
public DateTime TimeStamp { get; set; }
public T Variable { get; set; }
public string Name { get; set; }
}
And then you can instantiate the type using reflection methods:
Type type = Type.GetType("System.Int32");
Type genericizedType = typeof(OPC_UA<>).MakeGenericType(type);
dynamic opc_ua = Activator.CreateInstance(genericType);
opc_ua.Variable = 5; // For example
Here is the sample data from a collection. Basically the only thing that I am trying to do is read all of the data like this in as a "Student" but it is throwing an error for some reason. It works fine when I read them all in as Bson documents but that is not what I want to do. Here is the error:
An unhandled exception of type 'System.AggregateException' occurred in mscorlib.dll
Additional information: One or more errors occurred.
what am I doing wrong?
{
"_id" : 137,
"name" : "Tamika Schildgen",
"scores" : [
{
"type" : "exam",
"score" : 4.433956226109692
},
{
"type" : "quiz",
"score" : 65.50313785402548
},
{
"type" : "homework",
"score" : 89.5950384993947
}
]
}
static async Task MainAsync(string[] args)
{
var client = new MongoClient();
var db = client.GetDatabase("school");
var col = db.GetCollection<Student>("students");
var list = await col.Find(new BsonDocument())
.ToListAsync();
foreach(var doc in list)
{
Console.WriteLine(doc);
}
}
}
class Student
{
public ObjectId Id { get; set; }
public string name { get; set; }
public Scores[] scores { get; set; }
}
class Scores
{
public string type { get; set; }
public double score { get; set; }
}
The error lies in Id field type:
If you turn on the option of breaking execution when a CLR exception is thrown (Menu Debug|Exceptions), you will see a message similar to: "An error occurred while deserializing the Id property of class ConsoleApplication2.Student: Cannot deserialize a 'ObjectId' from BsonType 'Double'."
If you change the class Student to:
public class Student
{
public int Id { get; set; }
public string name { get; set; }
public Scores[] scores { get; set; }
}
the exception will not be thrown anymore.
(Additionally, to get readable results, you should probably override ToString() method for Student class).
I have some issue with mongo c# driver. I have such class:
class MongoEntity<T>
{
public ObjectId Id {get; set;}
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
public int Version { get; set; }
public T Entity { get; set; }
}
And during serialization my entities to database I have such document:
"_id" : "510654cf33d22e1774d5a2a9",
"CreatedAt" : {
"DateTime" : ISODate("2013-01-28T10:37:02.932Z"),
"Ticks" : NumberLong("634949662229321756")
},
"UpdatedAt" : {
"DateTime" : ISODate("2013-01-28T10:37:02.932Z"),
"Ticks" : NumberLong("634949662229321756")
},
"Version" : 1,
"Entity" : {
"EntityKey" : "tom#gmail.com",
"Password" : "ICy5YqxZB1uWSwcVLSNLcA==",
"Email" : "tom#gmail.com",
"Name" : "Tom Anderson"
}
What I really want is to have all properties of entity object in my document in the same level as properties of MongoEntity object like this:
"_id" : "510654cf33d22e1774d5a2a9",
"CreatedAt" : {
"DateTime" : ISODate("2013-01-28T10:37:02.932Z"),
"Ticks" : NumberLong("634949662229321756")
},
"UpdatedAt" : {
"DateTime" : ISODate("2013-01-28T10:37:02.932Z"),
"Ticks" : NumberLong("634949662229321756")
},
"Version" : 1,
"EntityKey" : "tom#gmail.com",
"Password" : "ICy5YqxZB1uWSwcVLSNLcA==",
"Email" : "tom#gmail.com",
"Name" : "Tom Anderson"
without Entity embedded object. How can I implement this in easiest way ?
P.S. What I am really looking for is some configuration of driver or writing custom serializer, maybe some workaround with dynamic, I do not want to change current class structure Enteties <-> MongoEntity
Thx for help.
There is no way to configure the built-in serializers to produce the document format you want (where the Entity fields are lifted one level up).
You would have to write a custom serializer, but it would be difficult because you either have to write a new serializer for each <T>, or you would have to write a sophisticated serializer that works for any <T>.
WiredPrairie's suggestion (Person : MongoEntityBase) is the recommended solution.
Just use a subclass of a base type that includes all of your required DB fields.
public class abstract MongoEntityBase
{
public ObjectId Id {get; set;}
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
public int Version { get; set; }
}
Then, use it:
public class Person : MongoEntityBase
{
public string Email { get; set; }
public string Name { get; set; }
}
The 10gen provided MongoDB C# driver works fine with that pattern.