I'm using v0.9 of the official MongoDB driver and i'm trying to read in a collection. I have a field in the database that I don't want to read into my object but I get the following error.
"Unexpected element: Network"
The collection looks like this in the database
Merchants
- _id
- Name
- Description
- Url
- Network
When I read it into C# I want to create an object called Merchant that has all of the same properties, except "Network". How do I do this?
There's an "IgnoreExtraElements" option on the BSON serializer which you can enable to prevent that error.
Either set it as an attribute on your Merchant class:
[BsonIgnoreExtraElements]
public Merchant {
// fields and properties
}
or in code if you're using class maps:
BsonClassMap.RegisterClassMap<Merchant>(cm => {
cm.AutoMap();
cm.SetIgnoreExtraElements(true);
});
Related
I'm using C# to supply a MongoDB Collection. The script must guarantee the uniqueness of each Bson document I ingest. To do this I have a field _id . However the _id field is included in another field. And as much as I saw documents are not unique. Documents look like this :
{"metadata" : { {"_id" , "id123"}, {"FileName","aFile42"} ... } ... }
How could I assure that I would get an exception if another Bson come by with the same _id without changing my document structure or without creating another collection as reference collection.
I want to deserialize an xml document to a class, which is genereated by the concerning xsd files. I don't have control over the contents of the xml-file.
During deserialization I run into an exception, because an enum value in the xml document does not meet the requiremnts of the xsd. Instead of breaking, i would like the deserialization to continue and just take the default value for any such errors. Is there any way to accomplish this behaviour?
edit:
For clarification, what i am trying to achieve: I want to read data from digital invoices. So the creation of the xml file is some kind of blackbox and can contain possibly flase values, even if the structure meets the standards. But that does not mean, that every value is flawed in that way. The exception prevents me from reading the correct values so i just want the deserialization to finish by somehow inserting the default values if such an error occurs.
Neither marking the values as obsolete, nor flagging them with XmlIgnore won't work, because the next xml i receive could contain correct values.
I hope that helped clarifying the problem.
Right now, im using the System.Xml.Serialization dll, but im willing to implement any library which can help me achieve the wanted behaviour.
The exception im getting:
"System.InvalidOperationException: Instance validation error: 'x' is
not a valid value for xType.."
The code that throws the exception:
XmlSerializer serializer = new xml.XmlSerializer(typeof(MyType));
MyType invoice = serializer.Deserialize(memoryStream) as MyType;
I know the code does not help very much, so I'll add the enum, that is currently problematic:
public enum PaymentMeansCodeContentType
{
[System.Xml.Serialization.XmlEnumAttribute("10")]
Item10,
[System.Xml.Serialization.XmlEnumAttribute("20")]
Item20,
[System.Xml.Serialization.XmlEnumAttribute("30")]
Item30,
[System.Xml.Serialization.XmlEnumAttribute("48")]
Item48,
[System.Xml.Serialization.XmlEnumAttribute("49")]
Item49,
[System.Xml.Serialization.XmlEnumAttribute("57")]
Item57,
[System.Xml.Serialization.XmlEnumAttribute("58")]
Item58,
[System.Xml.Serialization.XmlEnumAttribute("59")]
Item59,
ZZZ,
}
These are autogenerated from using the xsd command line tool:
https://learn.microsoft.com/de-de/dotnet/standard/serialization/xml-schema-definition-tool-xsd-exe
The xml i need to deserialize provides me with a '1', so clearly an invalid value. Still i need to access the other valid values from the xml and provide means for indicating which values are flawed.
You can mark the member Obsolete
public enum TypeEnum
{
Temperature,
Pressure,
[Obsolete]
Humidity
}
More info - docs
I still wasn't able to find the simple answer I was hoping for but managed to find a work around that worked for me. I ended up validating every enum in the XML file beforehand against the possible values. If the XML did not match the enum i saved the wrong value and node to a validation result set and overwrote the xml with the enum default value.
As Martin mentioned, it's a bit difficult to answer without proper context or sample code. However, you may want to look at the XmlIgnoreAttribute decorator on the property for the model. See the URL & code sample below for more details on how to use:
https://learn.microsoft.com/en-us/dotnet/api/system.xml.serialization.xmlattributes.xmlignore?view=netframework-4.8
using System;
using System.IO;
using System.Xml.Serialization;
// This is the class that will be serialized.
public class Group
{
// The GroupName value will be serialized--unless it's overridden.
public string GroupName;
/* This field will be ignored when serialized--
unless it's overridden. */
[XmlIgnoreAttribute]
public string Comment;
}
You can use Extended Xml Serializer library (avaliable via nuget) instead of the default XmlSerializer, with a custom converter that will set the default value in case of an error.
I suggest you store the value of the Enum as a string, and then parse it yourself. This is relatively simple to implement, here's an example:
public enum MyEnum
{
Default, //The default value to apply in the event of an invalid Enum value
[XmlEnumAttribute("10")]
Item10,
[XmlEnumAttribute("20")]
Item20
}
public class MyClass
{
public string Value { get; set; }
public MyEnum EnumValue => (MyEnum)(typeof(MyEnum).GetFields().FirstOrDefault(f =>
f.GetCustomAttribute<XmlEnumAttribute>()?.Name == Value)?
.GetValue(null) ?? MyEnum.Default);
}
Or if you prefer it you can also set a nullable Enum
public enum MyEnum
{
[XmlEnumAttribute("10")]
Item10,
[XmlEnumAttribute("20")]
Item20
}
public class MyClass
{
public string Value { get; set; }
public MyEnum? EnumValue => (MyEnum?)typeof(MyEnum).GetFields().FirstOrDefault(f =>
f.GetCustomAttribute<XmlEnumAttribute>()?.Name == Value)?
.GetValue(null);
}
I am using the MongoDB C# Driver v2.7.x, but I was wondering given a POCO class, is there anyway to raise warnings when querying on unmapped properties.
For example, I have the following class:
public class GroceryList
{
public string Name { get; set; }
[BsonIgnore]
public bool IsOwner { get; set; }
}
So whenever I store this object, IsOwner is not inserted into the database (see also the ignore member docs). However when I perform GetCollection<GroceryList>(..).AsQueryable().Where(gl => gl.IsOwner), this gets translated into {$match: {IsOwner: true}}, thus the element is still used in the query (see also the MongoDB LINQ docs).
Now in this trivial example it's easy to spot the problem; however when there's a few layers of indirection and a function starts returning an IQueryable instead of IEnumerable, it gets harder. So I would like to prevent the situation where ones could query on any field that's not mapped. Preferably through some convention (IMemberMapConvention).
After creating a small test project, I found that [BsonIgnore] would do exactly what I expected:
InvalidOperationException: {document}.IsOwner is not supported.
After some digging I found the problem was caused by how we ignore our members. In order to not have to reference Mongo in our domain layer, we introduced custom attributes that would do the same as Mongo's builtin attributes. However our implementation didn't correctly ignore members, but just disabled serialization for them:
if (mm.MemberInfo.IsDefined(typeof(CustomIgnoreMappingAttribute), true))
{
- memberMap.SetShouldSerializeMethod(o => false);
+ classMap.UnmapMember(memberMap.MemberInfo);
}
I'm working with latest C# driver for MongoDB. I know it's beta now, but I think I'm doing some basic things.
What's my problem: I'm trying to set representation for my Id field to ObjectId instead of string like it is described in documentation:
BsonClassMap.RegisterClassMap<Entity>(cm =>
{
cm.AutoMap();
cm.IdMemberMap.SetRepresentation(BsonType.ObjectId);
});
But I can not do that because method SetRepresentation() does not exist. And I can not find anything similar.
So I wonder, was this method removed?
Is there any other way to set representation besides attributes? I can not use attributes because I don't have access to Entity class, I'm working with derived class.
Thanks in advance!
I've spoken with the developer of the driver and he clarified this situation:
We've brought all those options into the serializers themselves, so, in this case, you'll want to set the serializer. IdMemberMap.SetSerializer(new StringSerializer(BsonType.ObjectId)); //It's a string which will be represented as an ObjectId in the database.
this works for me (v2.2)
cm.MapIdMember(c => c.Id)
.SetSerializer(new StringSerializer(BsonType.ObjectId))
.SetIdGenerator(StringObjectIdGenerator.Instance);
it's represent objectId in database (not string)
"_id" : ObjectId("56715ebddb6986202816e566"),
I'm trying to deserialize a collection to class.
It seems that in case one of the fields named Id, I will get the error:
base {"An error occurred while deserializing the Address property of
class Person.LicenseEntity: Element 'Id' does not match any field or
property of class Person.Address"} System.FormatException
{System.IO.FileFormatException}
However, changing the field name (e.g. to Idd) in both the class and the collection resolve the problem.
Is it possible that I'm not allowed to use the Id field?
I'm pretty sure this is because the Mongo C# driver deserializes the generated _id field from the document to the property named Id in your class. This means that your Id field has nowhere to go, and explains why changing the name of the Id to Idd allowed it to work.
As you are using a class called Address, I would perhaps name your field AddressId
Have a read of the Mongo C# Driver Docs I'm sure they will be a great help.