I am totally new to Mongo and trying to fix an issue on UpdateOne. Our environment is C#.
Another team built this and then made an update and now UpdateOne is failing with error
A write operation resulted in an error. WriteError: { Category : "Uncategorized", Code : 66, Message : "Performing an update on the path '_id' would modify the immutable field '_id'" }
- I can see _id in the documents.
- _id is not pulled as you can see in the below code “FindByName”. A projection is being used to exclude the _id so i don’t have this.
- When updating i get into an error as above
- I don’t want to remove the current item and then insert as new as suggested by some of the response i have found online
Here are the the main pieces of the code. How can “Update” method be modified so that above error doesn’t happen any more.?
public class MongoDocumentRepository<T> : IEntityRepository<T> where T : class, new()
{
readonly EntityEndpointOptions _options;
protected string Created_On = "CreatedOn";
protected string Updated_On = "UpdatedOn";
protected string MetaDataName = "Name";
protected ProjectionDefinition<T>? projectionItem = null;
protected string DocumentName = "";
public MongoDocumentRepository(IOptions<EntityEndpointOptions> options)
{
_options = options.Value;
this.DocumentName = GetDocumentName();
projectionItem = Builders<T>.Projection.Exclude("_id").Exclude("DocumentName");
}
private string GetDocumentName()
{
var entityInstance = new T();
if(entityInstance is IDbEntityMap map)
{
return map.DocumentName;
}
return null;
}
private IMongoDatabase CurrentStorage
{
get
{
return provider.GetDatabase(this.Storage);
}
}
private IMongoCollection<T> CurrentDocument
{
get
{
if (!Exist())
{
this.Create();
}
return CurrentStorage.GetCollection<T>(this.DocumentName);
}
}
private bool Exist()
{
var condition = new BsonDocument("name", this.DocumentName);
var collections = this.CurrentStorage.ListCollections(new ListCollectionsOptions { Filter = condition });
return collections.Any();
}
public string GetPropertyValue(T entity, string propertyName)
{
keyValue = entity.GetPropertyValue(propertyName);
return keyValue;
}
public T SetPropertyValue(T entity, string propertyName, object propertyValue)
{
entity.SetPropertyValue(propertyName, propertyValue);
return entity;
}
public T FindByName<T1>(T1 nameValue)
{
var condition = Builders<T>.Filter.Eq(this.MetaDataName, nameValue);
return this.CurrentDocument.Find(condition).Project<T>(projectionItem).FirstOrDefault();
}
public void Create(T entity)
{
SetPropertyValue(entity, this.Created_On, DateTime.UtcNow);
SetPropertyValue(entity, this.Updated_On, DateTime.UtcNow);
this.CurrentDocument.InsertOne(entity);
}
public void Update(T entity)
{
var myKeyValue = GetPropertyValue(entity, this.MetaDataName);
var condition = Builders<T>.Filter.Eq(this.MetaDataName, myKeyValue);
UpdateDefinition<T> updatedItem = null;
UpdateDefinitionBuilder<T> builder = new UpdateDefinitionBuilder<T>();
var properties = entity.GetType().GetProperties().Where(x => !x.GetGetMethod().IsStatic);
foreach (var property in properties)
{
var name = property.Name;
var value = property.GetValue(entity);
if (name.Equals(this.Updated_On, StringComparison.OrdinalIgnoreCase) || name.Equals(this.Created_On, StringComparison.OrdinalIgnoreCase) || name.Equals("CreatedBy", StringComparison.OrdinalIgnoreCase))
continue;
if (updatedItem == null)
{
updatedItem = updatedItem.Set(this.Updated_On, DateTime.UtcNow);
}
updatedItem = updatedItem.Set(name, value);
}
this.CurrentDocument.UpdateOne(condition, updatedItem);
}
}