I've got following structure in the database:
{
"_id" : ObjectId(""),
"title" : "something",
"id" : 1,
(...)
}
Basicly i want to retrive data from following collection to my Class:
[BsonIgnoreExtraElements]
public class Topic
{
[BsonElement("id")]
public int Id { get; set; }
[BsonElement("title")]
public string Name { get; set; }
}
The problem is this code doesn't work -> executes with error message:
Cannot deserialize a 'Int32' from BsonType 'ObjectId',
but this one does:
[BsonIgnoreExtraElements]
public class Topic
{
[BsonIgnore]
public int Id { get; set; }
[BsonElement("title")]
public string Name { get; set; }
[BsonElement("id")]
public int IdTest { get; set; }
Seems like deserialization desperatly tries to match class property with name "Id" with the ObjectId in database which is not correct because i explicitly declare that i want to match it with BsonElement("id") and not ("_id").
I appreciate any ideas how to make it works as I need to.
Your "_id" stored in your mongo document is of type BsonType.ObjectId so when deserializing, the Serializer try to find a property with the name "Id" and with type of ObjectId. In your case it found matched name but not the right type which is int (int32 type in your class): my suggestion is to change
public int Id { get; set; }
to
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
Or
public ObjectId Id { get; set; }
Or to make your class inheriting from class Entity if you use MongoRepository :
[BsonIgnoreExtraElements]
public class Topic : Entity
{
[BsonElement("title")]
public string Name { get; set; }
}
I ended up doing this:
public class Topic
{
public int Id { get; set; }
public string Name { get; set; }
}
[BsonIgnoreExtraElements]
public class TopicMapper
{
[BsonElement("title")]
public string Name { get; set; }
[BsonElement("id")]
public int Identity { get; set; }
}
and this:
var list = await col.Find(new BsonDocument()).ToListAsync().ConfigureAwait(false);
foreach(var doc in list)
{
if(doc.Name != null)
topics.Add(new Topic{
Id = doc.Identity,
Name = doc.Name
});
}
Related
I have a json file, where i have to validate a json attribute element value based on another json element attribute value. But if there json elements with the same name. It always takes the last value always instead of parsing the json data fully. Please guide me.
Below the sample json file
{
"PLMXML":{
"language":"en-us",
"author":"Developer",
"date":"2020-05-22",
"traverseRootRefs":"#id6",
"Operation":{
"id":"id21",
"subType":"BS4_BaOP",
"catalogueId":"70700000209604"
},
"Operation":{
"id":"id28",
"subType":"BS4_BaOP",
"catalogueId":"70700000209603"
},
"OperationRevision":{
"id":"id6",
"subType":"BS4_BaOPRevision",
"masterRef":"#id21",
"revision":"A1"
}
}
}
And below the code which im trying to use
public void Readjsonfile(string jsondata)
{
var message = JsonConvert.DeserializeObject<plmxmldatamodel>(jsondata);
if (String.Equals(message.PLMXML.traverseRootRefs.Substring(1), message.PLMXML.OperationRevision.id))
{
Console.WriteLine("Condtion1");
if (String.Equals(message.PLMXML.OperationRevision.masterRef.Substring(1), message.PLMXML.Operation.id))
{
Console.WriteLine("Condition_2");
//Do something based on the condtion
}
}
}
public class Operation
{
public string id { get; set; }
public string subType { get; set; }
public string catalogueId { get; set; }
}
public class OperationRevision
{
public string id { get; set; }
public string subType { get; set; }
public string masterRef { get; set; }
}
public class PLMXML
{
public string language { get; set; }
public string author { get; set; }
public string date { get; set; }
public string traverseRootRefs { get; set; }
public Operation Operation { get; set; }
public OperationRevision OperationRevision { get; set; }
}
public class plmxmldatamodel
{
public PLMXML PLMXML { get; set; }
}
When i try to dedug this in the second if condtion, the value for message.PLMXML.Operation.id is always id28 , because of which second if condition fails. While the first if condition is passed as there is only one message.PLMXML.OperationRevision.id. i wanted behaviour where it would check complete json data and check if message.PLMXML.Operation.id with value id21 is present or not , So my data gets passed. Please kindly guide me here.I am very new to C# here.
From my observation you have couple of issues.
What happen you have double keys, and your parser taking the last value not the first one.
First of all your json should be corrected. I assume you have access to change your json and operation should be an array like follow:
{
"PLMXML":{
"language":"en-us",
"author":"Developer",
"date":"2020-05-22",
"traverseRootRefs":"#id6",
"Operations":[
{
"id":"id21",
"subType":"BS4_BaOP",
"catalogueId":"70700000209604"
},
{
"id":"id28",
"subType":"BS4_BaOP",
"catalogueId":"70700000209603"
}
],
"OperationRevision":{
"id":"id6",
"subType":"BS4_BaOPRevision",
"masterRef":"#id21",
"revision":"A1"
}
}
}
When array in place than use an online tool like to validate your json and use this tool to create a model.
Your model will be like this:
public partial class PlmxmlDataModel
{
[JsonProperty("PLMXML")]
public Plmxml Plmxml { get; set; }
}
public partial class Plmxml
{
[JsonProperty("language")]
public string Language { get; set; }
[JsonProperty("author")]
public string Author { get; set; }
[JsonProperty("date")]
public DateTimeOffset Date { get; set; }
[JsonProperty("traverseRootRefs")]
public string TraverseRootRefs { get; set; }
[JsonProperty("Operations")]
public Operation[] Operations { get; set; }
[JsonProperty("OperationRevision")]
public OperationRevision OperationRevision { get; set; }
}
public partial class OperationRevision
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("subType")]
public string SubType { get; set; }
[JsonProperty("masterRef")]
public string MasterRef { get; set; }
[JsonProperty("revision")]
public string Revision { get; set; }
}
public partial class Operation
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("subType")]
public string SubType { get; set; }
[JsonProperty("catalogueId")]
public string CatalogueId { get; set; }
}
And your method like this:
public void Readjsonfile(string jsondata)
{
var message = JsonConvert.DeserializeObject<PlmxmlDataModel>(jsondata);
if (String.Equals(message.Plmxml.TraverseRootRefs.Substring(1), message.Plmxml.OperationRevision.Id))
{
Console.WriteLine("Condtion1");
if (String.Equals(message.Plmxml.OperationRevision.MasterRef.Substring(1), message.Plmxml.Operations[0].Id))
{
Console.WriteLine("Condition_2");
//Do something based on the condtion
}
}
}
Now in your method I am looking for array index 0 with contain id 28, but if you are look for id 28 in any of the array then you can do some thing like:
if (message.Plmxml.Operations.Any(e => e.Id == message.Plmxml.OperationRevision.MasterRef.Substring(1)))
this C# application needs to work with a MongoDB. When I try to add data, I get the error: E11000 duplicate key error collection: aap.Olas index: id dup key: { : BinData(3, 00000000000000000000000000000000) }
This is the code that adds Data to the DB
public void Add(IDataType item,string name)
{
IMongoCollection<IDataType> collection = db.GetCollection<IDataType>(name);
collection.InsertOne(item);
}
This is what the interface looks like.
using MongoDB.Bson.Serialization.Attributes;
using System;
namespace Labo04.GLOBAL
{
public interface IDataType
{
[BsonId]
Guid Id { get; set; }
}
}
This is the class Ola, the data I try to insert.
public class OLA : IDataType
{
[BsonId]
public Guid Id { get; set; }
public string Code { get; set; }
public string Naam { get; set; }
public int Studiepunten { get; set; }
public virtual List<Docent> Docenten { get; set; }
public virtual OPO Opo { get; set; }
public OLA()
{
}
public OLA(string code, string naam, int studiepunten, List<Docent> docenten, OPO opo)
{
this.Code = code;
this.Naam = naam;
this.Studiepunten = studiepunten;
this.Docenten = docenten;
this.Opo = opo;
}
}
How can I fix this.
I faced the same problem. It is because you are generating the Collection from IDataType:
db.GetCollection<IDataType>(name);
IDataType should be the final class object, so instead of passing the interface instance to this function, you can use generics:
public void Add<DataType>(DataType item,string name)
{
IMongoCollection<DataType> collection = db.GetCollection<DataType>(name);
collection.InsertOne(item);
}
I am working on an API in which I can receive a payload with several possible types based on their type. For example
public class Item{};
public class Book : Item{
public string author { get; set; }
public string title { get; set; }
}
public class Movie{
public string title { get; set; }
public string studio { get; set; }
}
public class VideoGame{
public string Name { get; set; }
}
public class StoreItem{
public string upc { get; set; }
public double price { get; set }
public Item item { get; set; }
}
What I would like to do is have My controller being able to accept a StoreItem object
for example
[HttpPost("postItemForSale")]
public object Post(StoreIrem item)
The way this would be resolved is base on a type enum, so the request json will look like this:
{
upc : "12345",
price : "99.99",
item : {
type : "videoGame",
name : "minesweeper"
}
}
My question is there anyway I can define a mapping, lets assume that the type field is an enum and I have a corresponding Model for each representation.
For deserialisation I usually use an object with the same property names as found in the JSon and JsonConvert.DeserializeObject<Des>(jsonstring).
But now I came across this:
{
"id": 0815,
"name": "whatever"
"addedInfo": {
"thisisinteresting": 4711,
"id_str": "2336"
}
}
How can I tell JSon.Net to pull the 'thisisinteresting' part of the sub category into a class like:
class Des
{
int id;
string name;
int thisisinteresting;
}
The trivial way would be to actually model your class to the JSON structure:
public class AddedInfo
{
public int thisisinteresting { get; set; }
public string id_str { get; set; }
}
public class RootObject
{
public int id { get; set; }
public string name { get; set; }
public AddedInfo addedInfo { get; set; }
}
Then add a property to the RootObject to emit the property:
public class RootObject
{
public int id { get; set; }
public string name { get; set; }
public AddedInfo addedInfo { get; set; }
[JsonIgnore]
public int thisisinteresting { get { return addedInfo.thisisinteresting; } }
}
There are alternatives like creating a custom serializer or using JObject and deserialize the structure yourself, but I won't go into that. If you need to parse the JSON anyway, the price to deserialize it entirely is small.
I have following scenario where I am getting OrderBase obstract class from ThirdParty library. And I have to inherit this abstract class into my model Order to get base attributes. Only below base attributes are required to be return as part of response.
Id
Name
OrderHistory
But actually it return all the base attributes as part of response due to inheritance. So is there any way by which we can restrict no of base attributes to be pass in the result without introduction of intermediate model(s) and mappings.
Code Sample- Third Party:
[DataContract]
[Serializable]
public abstract class OrderBase
{
public OrderBase(DatabaseObject obj)
{
this.Id = obj.Id;
this.Name = obj.Name;
this.Description = obj.Description;
this.ClosingDate = obj.ClosingDate;
this.Price = obj.Price;
}
[DataMember]
public string Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public string Description { get; set; }
[DataMember]
public decimal Price { get; set; }
[DataMember]
public string ClosingDate { get; set; }
}
public class DatabaseObject
{
public string Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public string ClosingDate { get; set; }
public string OrderHistory { get; set; }
}
Model:
[DataContract]
[Serializable]
public class Order : OrderBase
{
public Order(DatabaseObject dbObject)
: base(dbObject)
{
this.OrderHistory = dbObject.OrderHistory;
}
[DataMember]
public string OrderHistory { get; set; }
}
API Code:
public class OrderController : ApiController
{
public Order GetOrder()
{
var dbObj = new DatabaseObject
{
Id = "O001",
Name = "Masala Packets",
ClosingDate = "01/02/2016",
Description = "Payment Successful",
OrderHistory = "",
Price = 10000
};
var orderObj = new Order(dbObj);
return orderObj;
}
}
Current JSON Result:
{
"OrderHistory": "",
"Id": "O001",
"Name": "Masala Packets",
"Description": "Payment Successful",
"Price": 10000.0,
"ClosingDate": "01/02/2016"
}
Expected JSON Result:
{
"OrderHistory": "",
"Id": "O001",
"Name": "Masala Packets"
}
You're serializing your domain models directly. That may not be a good idea. It's better to create a view model to send your serialized data and you will have complete control of what to serialize as well as better separation of concerns. Something like an OrderDTO
public class OrderDTO {
public string Id { get; set; }
public string Name { get; set; }
public string OrderHistory { get; set; }
}
In your web api method:
public class OrderController : ApiController
{
public OrderDTO GetOrder()
{
// return an OrderDTO instead;
}
}
Or you can use JsonIgnore property to exclude properties from serialization in case you want to expose your domain classes:
[DataContract]
[Serializable]
public abstract class OrderBase
{
public OrderBase(DatabaseObject obj)
{
this.Id = obj.Id;
this.Name = obj.Name;
this.Description = obj.Description;
this.ClosingDate = obj.ClosingDate;
this.Price = obj.Price;
}
[DataMember]
public string Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
[JsonIgnore]
public string Description { get; set; }
[DataMember]
[JsonIgnore]
public decimal Price { get; set; }
[DataMember]
[JsonIgnore]
public string ClosingDate { get; set; }
}
Use the [ScriptIgnore] attribute on the property you don't want to serialize as JSON.
If you don't want to do this in the parent class, you should shadow or overload the property in your child class and add the attribute there.
How to exclude property from Json Serialization