private void InternalUpdate <T>(T entity, string name, ConcurrentSaveOptions saveOptions) // where T : IMongoEntity { var mongoEntity = (IMongoEntity)entity; MongoCollection <T> coll = Db.GetCollection <T>(name); IMongoQuery find; if (saveOptions == ConcurrentSaveOptions.ProtectServerChanges) { find = Query.And(Query.EQ("_id", mongoEntity._id), Query.EQ("_accessId", mongoEntity._accessId)); } else { find = Query.EQ("_id", mongoEntity._id); } string originalAccessId = mongoEntity._accessId; mongoEntity._accessId = BuildAccessId(); try { var wrap = new BsonDocumentWrapper(entity); var update = new UpdateDocument(wrap.ToBsonDocument()); WriteConcernResult res = coll.Update(find, update); if (res.DocumentsAffected == 1 && res.Ok) { // success return; } if (!res.Ok) { throw new MongoConcurrencyException(res.ErrorMessage); } // problem. is there just no document or is there a concurrency problem. // let's do a little work to no be overly agressive on the errors. bool isConcurrencyError = coll.Find(Query.EQ("_id", mongoEntity._id)).Any(); //coll.AsQueryable().Any(e => e._id == mongoEntity._id); if (isConcurrencyError) { throw new MongoConcurrencyException("Entity modified by other writer since being retreived from db: id = " + mongoEntity._id); } throw new MongoException("Cannot update entity (no entity with ID " + mongoEntity._id + " exists in the db."); } catch { mongoEntity._accessId = originalAccessId; throw; } }
public void Save <T>(T entity, string connectionName, ConcurrentSaveOptions saveOptions) where T : class { if (entity == null) { throw new ArgumentNullException("entity"); } var mongoEntity = entity as IMongoEntity; if (mongoEntity == null) { throw new InvalidOperationException("Cannot save entity in ConcurrentDataContext. " + typeof(T).Name + " does not implemented IMongoEntity."); } if (mongoEntity._id == ObjectId.Empty) { InternalInsert(entity, connectionName); } else { InternalUpdate(entity, connectionName, saveOptions); } }
/// <summary> /// Save changes to entity back to MongoDB with concurrency protection /// specified by saveOptions. If you want to *overwrite* changes made /// on the server use ConcurrentSaveOptions.OverwriteServerChanges. /// </summary> /// <typeparam name="T">Type of entity</typeparam> /// <param name="entity">The entity to be saved</param> /// <param name="saveOptions"> /// Enables or disables concurrency projected, /// ConcurrentSaveOptions.ProtectServerChanges is recommended. /// </param> public void Save <T>(T entity, ConcurrentSaveOptions saveOptions) where T : class { Save(entity, GetCollectionName <T>(), saveOptions); }