Reputation: 21719
I have a class that has an enum property inside it. The property is written as a string to the database when saving the whole document because of the attribute in the .NET representation of the document below
public enum Status { Good, Bad }
public class Document
{
[BsonRepresentation(BsonType.String)]
public Status Status { get; set; }
// ...
}
Later when I want to update the value within a document without saving the whole document, I construct a filter like this:
var builder = Builders<T>.Update;
var filter = builder.Set(new StringFieldDefinition<T, Status>(fieldName), (Status)value);
var result = await Context.Collection.UpdateManyAsync(filter, update);
This unfortunately writes the integer value of the enum.
If I change the filter to this
var filter = builder.Set(new StringFieldDefinition<T, Status>(fieldName), value.ToString());
The driver will throw an InvalidCastException
. How can I construct the filter properly? Is there another way to set the enum value directly without replacing the document?
It occurred to me that there might be a way to relate the single-field behavior back to the attribute on the whole document, but I can't seem to find out how to do that.
Upvotes: 5
Views: 3103
Reputation: 5679
once you decorate an enum property with [BsonRepresentation(BsonType.String)]
you don't need to do any casts in your code. the attribute instructs the driver to store the stirng name of the enum value in the db and when deserializing it, set it back to the appropriate enum value. so your application code can just deal with enums.
var statusValue = Status.Good;
var filter = Builders<Document>.Filter.Eq(d => d.Status, Status.Bad);
var update = Builders<Document>.Update.Set(d => d.Status, statusValue);
collection.UpdateMany(filter, update);
test program:
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Entities;
using MongoDB.Entities.Core;
namespace StackOverFlow
{
public enum Status { Good, Bad }
public class Document : Entity
{
[BsonRepresentation(BsonType.String)]
public Status Status { get; set; }
}
public static class Program
{
private static void Main()
{
new DB("test");
new Document { Status = Status.Bad }.Save();
var statusValue = Status.Good;
DB.Update<Document>()
.Match(f => f.Eq(d => d.Status, Status.Bad))
.Modify(b => b.Set(d => d.Status, statusValue))
.Execute();
}
}
}
Upvotes: 3
Reputation: 13103
How about this: (Not tested)
await collection.UpdateManyAsync(
Builders<BsonDocument>.Filter.Eq(fieldName, (Status)value)), //filter definition
Builders<BsonDocument>.Update.Set(fieldName, (Status)value));
Upvotes: 0
Reputation: 10098
C# enums are represented by integers. By default the first enum is 0, and the second is 1, and so on. You can assign specific integer values to enum entries but again they are interpreted as integers, not strings. To get the string value which matches your enum entry you must use the enum.parse
method.
I do not have a C# environment available at the moment, so I cannot test my suggestion, but please try this...
var filter = builder.Set(new StringFieldDefinition<T, String>(fieldName), Enum.Parse(typeof(Status), value));
Upvotes: 0