Reputation: 423
I have a C# class with some fields and some of them are null. Those that are null I do not want to be inserted into db with null value. I do not want them inserted into db at all. How do I achieve that?
class User
{
public string FirstName;
public string LastName;
public string MidName;
}
Not every user has a MidName, but Mongo inserts into db with null value on MidName field.
Upvotes: 14
Views: 16630
Reputation: 71
The best solution I could come up with to prevent the insertion of Null & Empty values was by creating a custom Attribute
that inherits the IBsonMemberMapAttribute
interface and uses the BsonMemberMap.SetShouldSerializeMethod()
method. Both come from the MongoDB.Bson.Serialization
namespace which comes from the MongoDb.Driver Nuget Package.
Step 1: Create the Custom Attribute
// BsonIgnoreIfNullOrEmptyAttribute.cs
using MongoDB.Bson.Serialization;
using System.Collections;
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public class BsonIgnoreIfNullOrEmptyAttribute : Attribute, IBsonMemberMapAttribute
{
public void Apply(BsonMemberMap memberMap)
{
_ = memberMap.SetShouldSerializeMethod(classObj =>
{
string propertyName = memberMap.MemberName;
var propertyValue = classObj?.GetType().GetProperty(propertyName).GetValue(classObj);
return propertyValue switch
{
null => false,
string value when string.IsNullOrEmpty(value) => false,
ICollection collection when collection.Count == 0 => false,
_ => true
};
});
}
}
Explanation: Inside the Apply()
method, I used memberMap.MemberName
which gives you the propertyName
of the property that has the [BsonIgnoreIfNullOrEmpty] Attribute
and then I used reflections to get the value of that property when it is read by the MongoDB's IBsonSerializer
(which is determined by the BsonClassMap
). Next, I created a switch expression that will validate the value of the property and check if the value is null or empty for string
and ICollection
types.
Note: Returning false
inside the SetShouldSerializeMethod() method
means that it will NOT serialize the property.
Step 2: Use the Custom Attribute on the desired properties.
It will behave similarly to the other [BsonIgnore...]
Attributes
// User.cs
using MongoDB.Bson.Serialization.Attributes;
public class User
{
[BsonIgnoreIfDefault]
public Guid Id { get; set; }
[BsonIgnoreIfNullOrEmpty]
public string FirstName { get; set; }
[BsonIgnoreIfNullOrEmpty]
public string LastName { get; set; }
[BsonIgnoreIfNullOrEmpty]
public string MiddleName { get; set; }
[BsonIgnoreIfDefault]
public int Age { get; set; }
[BsonIgnoreIfDefault]
public DateTime BirthDate { get; set; }
[BsonIgnoreIfNull]
public Department Department { get; set; }
[BsonIgnoreIfNullOrEmpty]
public List<Guid> FriendIds { get; set; }
}
Upvotes: 0
Reputation: 151586
Using the aptly named [BsonIgnoreIfNull]
attribute:
class User
{
public string FirstName;
public string LastName;
[BsonIgnoreIfNull]
public string MidName;
}
Upvotes: 24
Reputation: 17637
Ensure you are registering the new convention pack early enough. If any classes have already been mapped before you register the new convention pack they won't be updated.
Here's my test code:
public class C
{
public int Id { get; set; }
public string S { get; set; }
}
public static class Program
{
public static void Main(string[] args)
{
ConventionRegistry.Register(
"Ignore null values",
new ConventionPack
{
new IgnoreIfNullConvention(true)
},
t => true);
var client = new MongoClient("mongodb://localhost");
var server = client.GetServer();
var database = server.GetDatabase("test");
var collection = database.GetCollection<C>("test");
collection.Drop();
collection.Insert(new C { Id = 1, S = null });
Console.WriteLine("Press Enter to continue.");
Console.ReadLine();
}
}
The following document was inserted into the database:
db.test.find()
{ "_id" : 1 }
Source: https://groups.google.com/forum/#!topic/mongodb-user/7-NFXBNeEXs
Upvotes: 12