internal void SetFieldValue(FieldInfo field, object value, SyncContext syncContext, RemovalContext removalContext) { if (field.ReflectedType.IsInterface) { field = TypeInfo.FieldMap[field]; } SystemSetValueAttempt(field, value); var fieldAccessor = GetFieldAccessor(field); object oldValue = GetFieldValue(field); // Handling 'OldValue != NewValue' problem for structures var o = oldValue as Structure; if (o != null) { oldValue = Activator.CreateStructure(Session, o.GetType(), o.Tuple.ToRegular()); } try { var operations = Session.Operations; var scope = operations.BeginRegistration(Operations.OperationType.System); try { var entity = this as Entity; if (entity != null) { if (operations.CanRegisterOperation) { operations.RegisterOperation(new EntityFieldSetOperation(entity.Key, field, value)); } var entityValue = value as IEntity; if (entityValue != null) { var valueKey = entityValue.Key; Session.ReferenceFieldsChangesRegistry.Register(entity.Key, valueKey, field); } } else { var persistent = this; var currentField = field; var structure = persistent as Structure; while (structure != null && structure.Owner != null) { var pair = new Pair <FieldInfo>(structure.Field, currentField); currentField = structure.Owner.TypeInfo.StructureFieldMapping[pair]; persistent = structure.Owner; structure = persistent as Structure; } entity = persistent as Entity; if (entity != null) { if (operations.CanRegisterOperation) { operations.RegisterOperation(new EntityFieldSetOperation(entity.Key, currentField, value)); } var entityValue = value as IEntity; if (entityValue != null) { var valueKey = entityValue.Key; Session.ReferenceFieldsChangesRegistry.Register(entity.Key, valueKey, field); } } } if (fieldAccessor.AreSameValues(oldValue, value)) { operations.NotifyOperationStarting(false); scope.Complete(); return; } { SystemBeforeSetValue(field, value); operations.NotifyOperationStarting(false); AssociationInfo association = null; entity = value as Entity ?? oldValue as Entity; if (entity != null) { association = field.GetAssociation(entity.TypeInfo); } if (association != null && association.IsPaired) { Key currentKey = GetReferenceKey(field); Key newKey = null; var newReference = (Entity)(object)value; if (newReference != null) { newKey = newReference.Key; } if (currentKey != newKey) { Session.PairSyncManager.ProcessRecursively(syncContext, removalContext, OperationType.Set, association, (Entity)this, newReference, () => { SystemBeforeTupleChange(); fieldAccessor.SetUntypedValue(this, value); SystemTupleChange(); }); } } else { // The method of Equals(object, object) wrapped with in a block 'try catch', // because that for data types NpgsqlPath and NpgsqlPolygon which are defined without an initial value it works incorrectly. bool canBeEqual; try { canBeEqual = Equals(value, oldValue); } catch (Exception) { canBeEqual = false; } if (!canBeEqual || field.IsStructure) { SystemBeforeTupleChange(); value = AdjustFieldValue(field, oldValue, value); fieldAccessor.SetUntypedValue(this, value); SystemTupleChange(); } } if (removalContext != null) { // Postponing finalizers (events) removalContext.EnqueueFinalizer(() => { try { try { SystemSetValue(field, oldValue, value); SystemSetValueCompleted(field, oldValue, value, null); scope.Complete(); } finally { scope.DisposeSafely(); } } catch (Exception e) { SystemSetValueCompleted(field, oldValue, value, e); throw; } }); return; } SystemSetValue(field, oldValue, value); SystemSetValueCompleted(field, oldValue, value, null); } scope.Complete(); } finally { if (removalContext == null) { scope.DisposeSafely(); } } } catch (Exception e) { SystemSetValueCompleted(field, oldValue, value, e); throw; } }
internal bool Remove(Entity item, SyncContext syncContext, RemovalContext removalContext) { if (!Contains(item)) { return(false); } try { var operations = Session.Operations; var scope = operations.BeginRegistration(Operations.OperationType.System); try { var itemKey = item.Key; if (operations.CanRegisterOperation) { operations.RegisterOperation(new EntitySetItemRemoveOperation(Owner.Key, Field, itemKey)); } SystemBeforeRemove(item); int? index = null; var association = Field.GetAssociation(item.TypeInfo); Action finalizer = () => { var auxiliaryType = association.AuxiliaryType; if (auxiliaryType != null && association.IsMaster) { var combinedTuple = auxilaryTypeKeyTransform.Apply( TupleTransformType.Tuple, Owner.Key.Value, itemKey.Value); var combinedKey = Key.Create( Session.Domain, Session.StorageNodeId, auxiliaryType, TypeReferenceAccuracy.ExactType, combinedTuple); Session.RemoveOrCreateRemovedEntity(auxiliaryType.UnderlyingType, combinedKey, EntityRemoveReason.Association); } var state = State; index = GetItemIndex(state, itemKey); state.Remove(itemKey); Session.EntitySetChangeRegistry.Register(state); }; operations.NotifyOperationStarting(); if (association.IsPaired) { Session.PairSyncManager.ProcessRecursively(syncContext, removalContext, OperationType.Remove, association, Owner, item, finalizer); } else { finalizer.Invoke(); } if (removalContext != null) { // Postponing finalizers (events) removalContext.EnqueueFinalizer(() => { try { try { index = GetItemIndex(State, itemKey); // Necessary, since index can be already changed if (!skipOwnerVersionChange) { Owner.UpdateVersionInfo(Owner, Field); } SystemRemove(item, index); SystemRemoveCompleted(item, null); scope.Complete(); } finally { scope.DisposeSafely(); } } catch (Exception e) { SystemRemoveCompleted(item, e); throw; } }); return(true); } if (!skipOwnerVersionChange) { Owner.UpdateVersionInfo(Owner, Field); } SystemRemove(item, index); SystemRemoveCompleted(item, null); scope.Complete(); return(true); } finally { if (removalContext == null) { scope.DisposeSafely(); } } } catch (Exception e) { SystemRemoveCompleted(item, e); throw; } }