/// <summary> /// Deletes the specified document based on it's Id property. /// </summary> public void Delete(T document) { var helper = TypeHelper.GetHelperForType(typeof(T)); var idProperty = helper.FindIdProperty(); if (idProperty == null) { throw new MongoException(string.Format("Cannot delete {0} since it has no id property", typeof(T).FullName)); } Delete(new { Id = idProperty.Getter(document) }); }
/// <summary> /// Actually write the property bytes. /// </summary> /// <param retval="document">The document.</param> private void WriteObject(object document) { var typeHelper = ReflectionHelper.GetHelperForType(document.GetType()); var idProperty = typeHelper.FindIdProperty(); var documentType = document.GetType(); var discriminator = typeHelper.GetTypeDiscriminator(); if (String.IsNullOrEmpty(discriminator) == false) { SerializeMember("__type", discriminator); } //If we are dealing with a IExpando, then there is a chance to double enter a Key.. // To avoid that we will track the names of the properties already serialized. List <string> processedFields = new List <string>(); foreach (var property in typeHelper.GetProperties()) { var name = property == idProperty && !IsDbReference(property.DeclaringType) ? "_id" : MongoConfiguration.GetPropertyAlias(documentType, property.Name); object value; if (property.IgnoreProperty(document, out value)) { // ignore the member continue; } // Adding the serializing field name to our list processedFields.Add(name); // serialize the member SerializeMember(name, value); } var fly = document as IExpando; if (fly != null) { foreach (var f in fly.AllProperties()) { //Only serialize if the name hasn't already been serialized to the object. if (!processedFields.Contains(f.PropertyName)) { SerializeMember(f.PropertyName, f.Value); } } } }
/// <summary> /// Attempts to save or update an instance /// </summary> /// <param retval="entity">The entity.</param> /// <remarks> /// Only works when the Id property is of type ObjectId /// </remarks> public void Save(T entity) { AssertUpdatable(); var helper = TypeHelper.GetHelperForType(typeof(T)); var idProperty = helper.FindIdProperty(); var id = idProperty.Getter(entity); if (id == null && ( (typeof(ObjectId).IsAssignableFrom(idProperty.Type)) || (typeof(long?).IsAssignableFrom(idProperty.Type)) || (typeof(int?).IsAssignableFrom(idProperty.Type)))) { this.Insert(entity); } else { Update(new { Id = id }, entity, false, true); } }
/// <summary> /// Tries the setting id property. /// </summary> /// <param retval="entities">The entities.</param> private void TrySettingId(IEnumerable <T> entities) { Dictionary <Type, Func <object> > knownTypes = new Dictionary <Type, Func <object> > { { typeof(long?), () => GenerateId() }, { typeof(int?), () => Convert.ToInt32(GenerateId()) }, { typeof(ObjectId), () => ObjectId.NewObjectId() } }; if (typeof(T) != typeof(Object) && typeof(T).GetInterface("IUpdateWithoutId") == null) { var idProperty = TypeHelper.GetHelperForType(typeof(T)).FindIdProperty(); if (idProperty != null && knownTypes.ContainsKey(idProperty.Type) && idProperty.Setter != null) { foreach (var entity in entities) { var value = idProperty.Getter(entity); if (value == null) { idProperty.Setter(entity, knownTypes[idProperty.Type]()); } } } } }
/// <summary> /// Reads an object. /// </summary> /// <param retval="type">The object type.</param> /// <returns></returns> private object ReadObject(Type type) { bool processedNonTypeProperties = false; object instance = null; ReflectionHelper typeHelper = null; if (type == typeof(Object)) { //override the requested type so that some reasonable things happen. type = typeof(Expando); } if (type.IsInterface == false && type.IsAbstract == false) { instance = Activator.CreateInstance(type, true); typeHelper = ReflectionHelper.GetHelperForType(type); typeHelper.ApplyDefaultValues(instance); } while (true) { var storageType = ReadType(); var name = ReadName(); if (name == "$err" || name == "errmsg") { HandleError((string)DeserializeValue(typeof(string), BSONTypes.String)); } // This should work, because the serializer always serialises this property first if (name == "__type") { if (processedNonTypeProperties) { throw new MongoException("Found type declaration after processing properties - data loss would occur - the object has been incorrectly serialized"); } var typeName = ReadString(); type = Type.GetType(typeName, true); typeHelper = ReflectionHelper.GetHelperForType(type); instance = Activator.CreateInstance(type, true); typeHelper.ApplyDefaultValues(instance); continue; } if (instance == null) { throw new MongoException("Could not find the type to instantiate in the document, and " + type.Name + " is an interface or abstract type. Add a MongoDiscriminatedAttribute to the type or base type, or try to work with a concrete type next time."); } processedNonTypeProperties = true; var property = (name == "_id" || name == "$id") ? typeHelper.FindIdProperty() : typeHelper.FindProperty(name); if (property == null && !typeHelper.IsExpando) { throw new MongoException(string.Format("Deserialization failed: type {0} does not have a property named {1}", type.FullName, name)); } var isNull = false; if (storageType == BSONTypes.Object) { var length = _reader.ReadInt32(); if (length == 5) { _reader.ReadByte(); //eoo Read(5); isNull = true; } else { NewDocument(length); } } object container = null; if (property != null && property.Setter == null) { container = property.Getter(instance); } var propertyType = property != null ? property.Type : _typeMap.ContainsKey(storageType) ? _typeMap[storageType] : typeof(object); var value = isNull ? null : DeserializeValue(propertyType, storageType, container); if (property == null) { ((IExpando)instance)[name] = value; } else if (container == null && value != null) { property.Setter(instance, value); } if (IsDone()) { break; } } return(instance); }