Exemple #1
0
 public InternalEntityEntry(InternalContext internalContext, IEntityStateEntry stateEntry)
 {
     this._internalContext = internalContext;
     this._stateEntry      = stateEntry;
     this._entity          = stateEntry.Entity;
     this._entityType      = ObjectContextTypeCache.GetObjectType(this._entity.GetType());
 }
 internal ExtractedStateEntry(EntityState state, PropagatorResult original, PropagatorResult current, IEntityStateEntry source)
 {
     State    = state;
     Original = original;
     Current  = current;
     Source   = source;
 }
Exemple #3
0
        internal ExtractedStateEntry(UpdateTranslator translator, IEntityStateEntry stateEntry)
        {
            this.State  = stateEntry.State;
            this.Source = stateEntry;
            switch (stateEntry.State)
            {
            case EntityState.Unchanged:
                this.Original = translator.RecordConverter.ConvertOriginalValuesToPropagatorResult(stateEntry, ModifiedPropertiesBehavior.NoneModified);
                this.Current  = translator.RecordConverter.ConvertCurrentValuesToPropagatorResult(stateEntry, ModifiedPropertiesBehavior.NoneModified);
                break;

            case EntityState.Added:
                this.Original = (PropagatorResult)null;
                this.Current  = translator.RecordConverter.ConvertCurrentValuesToPropagatorResult(stateEntry, ModifiedPropertiesBehavior.AllModified);
                break;

            case EntityState.Deleted:
                this.Original = translator.RecordConverter.ConvertOriginalValuesToPropagatorResult(stateEntry, ModifiedPropertiesBehavior.AllModified);
                this.Current  = (PropagatorResult)null;
                break;

            case EntityState.Modified:
                this.Original = translator.RecordConverter.ConvertOriginalValuesToPropagatorResult(stateEntry, ModifiedPropertiesBehavior.SomeModified);
                this.Current  = translator.RecordConverter.ConvertCurrentValuesToPropagatorResult(stateEntry, ModifiedPropertiesBehavior.SomeModified);
                break;

            default:
                this.Original = (PropagatorResult)null;
                this.Current  = (PropagatorResult)null;
                break;
            }
        }
Exemple #4
0
        public void GetChangesShouldBeUsedAsMainChanges()
        {
            bool isInvoked = false;
            bool isInvokedChangesApplied = false;

            StateManager.CreateSnapshot = o => new EntitySnapshotMock();
            var entries = new IEntityStateEntry[0];
            var entity  = new object();

            var viewModel = GetViewModel <EditableViewModelMock>();

            viewModel.GetChangesDelegate = o =>
            {
                isInvoked = true;
                o.ShouldEqual(entity);
                return(entries);
            };
            viewModel.OnChangesAppliedDelegate = list =>
            {
                list.ShouldEqual(entries);
                isInvokedChangesApplied = true;
            };

            viewModel.InitializeEntity(entity, false);
            viewModel.ApplyChanges().ShouldEqual(entries);
            isInvoked.ShouldBeTrue();
            isInvokedChangesApplied.ShouldBeTrue();
        }
 internal ExtractedStateEntry(EntityState state, PropagatorResult original, PropagatorResult current, IEntityStateEntry source)
 {
     State = state;
     Original = original;
     Current = current;
     Source = source;
 }
        private PropagatorResult CreateSimpleResult(
            IEntityStateEntry stateEntry,
            IExtendedDataRecord record,
            ExtractorMetadata.MemberInformation memberInformation,
            int identifier,
            bool isModified,
            int recordOrdinal,
            object value)
        {
            CurrentValueRecord record1 = record as CurrentValueRecord;
            PropagatorFlags    flags   = memberInformation.Flags;

            if (!isModified)
            {
                flags |= PropagatorFlags.Preserve;
            }
            if (-1 != identifier)
            {
                PropagatorResult owner = !memberInformation.IsServerGenerated && !memberInformation.IsForeignKeyMember || record1 == null?PropagatorResult.CreateKeyValue(flags, value, stateEntry, identifier) : PropagatorResult.CreateServerGenKeyValue(flags, value, stateEntry, identifier, recordOrdinal);

                this.m_translator.KeyManager.RegisterIdentifierOwner(owner);
                return(owner);
            }
            if ((memberInformation.IsServerGenerated || memberInformation.IsForeignKeyMember) && record1 != null)
            {
                return(PropagatorResult.CreateServerGenSimpleValue(flags, value, record1, recordOrdinal));
            }
            return(PropagatorResult.CreateSimpleValue(flags, value));
        }
        internal void RegisterKeyValueForAddedEntity(IEntityStateEntry addedEntry)
        {
            EntityKey entityKey = addedEntry.EntityKey;
            ReadOnlyMetadataCollection <EdmMember> keyMembers = addedEntry.EntitySet.ElementType.KeyMembers;
            CurrentValueRecord currentValues = addedEntry.CurrentValues;

            object[] compositeKeyValues = new object[keyMembers.Count];
            bool     flag  = false;
            int      index = 0;

            for (int count = keyMembers.Count; index < count; ++index)
            {
                int ordinal = currentValues.GetOrdinal(keyMembers[index].Name);
                if (currentValues.IsDBNull(ordinal))
                {
                    flag = true;
                    break;
                }
                compositeKeyValues[index] = currentValues.GetValue(ordinal);
            }
            if (flag)
            {
                return;
            }
            EntityKey key = compositeKeyValues.Length == 1 ? new EntityKey(addedEntry.EntitySet, compositeKeyValues[0]) : new EntityKey(addedEntry.EntitySet, compositeKeyValues);

            if (this._valueKeyToTempKey.ContainsKey(key))
            {
                this._valueKeyToTempKey[key] = (EntityKey)null;
            }
            else
            {
                this._valueKeyToTempKey.Add(key, entityKey);
            }
        }
Exemple #8
0
 internal static PropagatorResult CreateKeyValue(
     PropagatorFlags flags,
     object value,
     IEntityStateEntry stateEntry,
     int identifier)
 {
     return((PropagatorResult) new PropagatorResult.KeyValue(flags, value, stateEntry, identifier, (PropagatorResult.KeyValue)null));
 }
            internal KeyValue(PropagatorFlags flags, object value, IEntityStateEntry stateEntry, int identifier, KeyValue next)
                : base(flags, value)
            {
                DebugCheck.NotNull(stateEntry);

                m_stateEntry = stateEntry;
                m_identifier = identifier;
                m_next       = next;
            }
Exemple #10
0
 internal static PropagatorResult CreateServerGenKeyValue(
     PropagatorFlags flags,
     object value,
     IEntityStateEntry stateEntry,
     int identifier,
     int recordOrdinal)
 {
     return((PropagatorResult) new PropagatorResult.ServerGenKeyValue(flags, value, stateEntry, identifier, recordOrdinal, (PropagatorResult.KeyValue)null));
 }
            private static void ProcessReferenceCandidate(
                EntityKey source,
                HashSet <IEntityStateEntry> stateEntries,
                Dictionary <AssociationEndMember, IEntityStateEntry> currentReferenceEnd,
                Dictionary <AssociationEndMember, IEntityStateEntry> originalReferenceEnd,
                AssociationEndMember endMember,
                IEntityStateEntry candidateEntry)
            {
                Func <DbDataRecord, int, EntityKey> getEntityKey             = (record, ordinal) => (EntityKey)record[ordinal];
                Action <DbDataRecord, Action <IEntityStateEntry> > findMatch = (record, registerTarget) =>
                {
                    // find the end corresponding to the 'to' end
                    var toOrdinal = record.GetOrdinal(endMember.Name);
                    Debug.Assert(
                        -1 != toOrdinal,
                        "to end of relationship doesn't exist in record");

                    // the 'from' end must be the other end
                    var fromOrdinal = 0 == toOrdinal ? 1 : 0;

                    if (getEntityKey(record, fromOrdinal) == source)
                    {
                        stateEntries.Add(candidateEntry);
                        registerTarget(candidateEntry);
                    }
                };

                switch (candidateEntry.State)
                {
                case EntityState.Unchanged:
                    findMatch(
                        candidateEntry.CurrentValues,
                        (target) =>
                    {
                        currentReferenceEnd.Add(endMember, target);
                        originalReferenceEnd.Add(endMember, target);
                    });
                    break;

                case EntityState.Added:
                    findMatch(
                        candidateEntry.CurrentValues,
                        (target) => currentReferenceEnd.Add(endMember, target));
                    break;

                case EntityState.Deleted:
                    findMatch(
                        candidateEntry.OriginalValues,
                        (target) => originalReferenceEnd.Add(endMember, target));
                    break;

                default:
                    break;
                }
            }
        /// <summary>
        ///     Initializes a new instance of the <see cref="InternalEntityEntry" /> class.
        /// </summary>
        /// <param name="internalContext"> The internal context. </param>
        /// <param name="stateEntry"> The state entry. </param>
        public InternalEntityEntry(InternalContext internalContext, IEntityStateEntry stateEntry)
        {
            DebugCheck.NotNull(internalContext);
            DebugCheck.NotNull(stateEntry);
            Debug.Assert(stateEntry.Entity != null);

            _internalContext = internalContext;
            _stateEntry = stateEntry;
            _entity = stateEntry.Entity;
            _entityType = ObjectContextTypeCache.GetObjectType(_entity.GetType());
        }
Exemple #13
0
 internal ServerGenKeyValue(
     PropagatorFlags flags,
     object value,
     IEntityStateEntry stateEntry,
     int identifier,
     int recordOrdinal,
     PropagatorResult.KeyValue next)
     : base(flags, value, stateEntry, identifier, next)
 {
     this.m_recordOrdinal = recordOrdinal;
 }
        /// <summary>
        ///     Initializes a new instance of the <see cref = "InternalEntityEntry" /> class.
        /// </summary>
        /// <param name = "internalContext">The internal context.</param>
        /// <param name = "stateEntry">The state entry.</param>
        public InternalEntityEntry(InternalContext internalContext, IEntityStateEntry stateEntry)
        {
            //Contract.Requires(internalContext != null);
            //Contract.Requires(stateEntry != null);
            Contract.Assert(stateEntry.Entity != null);

            _internalContext = internalContext;
            _stateEntry = stateEntry;
            _entity = stateEntry.Entity;
            _entityType = ObjectContextTypeCache.GetObjectType(_entity.GetType());
        }
        // <summary>
        // Initializes a new instance of the <see cref="InternalEntityEntry" /> class.
        // </summary>
        // <param name="internalContext"> The internal context. </param>
        // <param name="stateEntry"> The state entry. </param>
        public InternalEntityEntry(InternalContext internalContext, IEntityStateEntry stateEntry)
        {
            DebugCheck.NotNull(internalContext);
            DebugCheck.NotNull(stateEntry);
            Debug.Assert(stateEntry.Entity != null);

            _internalContext = internalContext;
            _stateEntry      = stateEntry;
            _entity          = stateEntry.Entity;
            _entityType      = ObjectContextTypeCache.GetObjectType(_entity.GetType());
        }
Exemple #16
0
 internal KeyValue(
     PropagatorFlags flags,
     object value,
     IEntityStateEntry stateEntry,
     int identifier,
     PropagatorResult.KeyValue next)
     : base(flags, value)
 {
     this.m_stateEntry = stateEntry;
     this.m_identifier = identifier;
     this.m_next       = next;
 }
Exemple #17
0
 public InternalEntityEntry(InternalContext internalContext, object entity)
 {
     this._internalContext = internalContext;
     this._entity          = entity;
     this._entityType      = ObjectContextTypeCache.GetObjectType(this._entity.GetType());
     this._stateEntry      = this._internalContext.GetStateEntry(entity);
     if (this._stateEntry != null)
     {
         return;
     }
     this._internalContext.Set(this._entityType).InternalSet.Initialize();
 }
Exemple #18
0
        /// <summary>
        /// Registers an added entity so that it can be matched by a foreign key lookup.
        /// </summary>
        internal void RegisterKeyValueForAddedEntity(IEntityStateEntry addedEntry)
        {
            Debug.Assert(null != addedEntry);
            Debug.Assert(!addedEntry.IsRelationship);
            Debug.Assert(!addedEntry.IsKeyEntry);
            Debug.Assert(addedEntry.EntityKey.IsTemporary);

            // map temp key to 'value' key (if all values of the key are non null)
            EntityKey tempKey = addedEntry.EntityKey;
            EntityKey valueKey;
            var       keyMembers    = addedEntry.EntitySet.ElementType.KeyMembers;
            var       currentValues = addedEntry.CurrentValues;

            object[] keyValues    = new object[keyMembers.Count];
            bool     hasNullValue = false;

            for (int i = 0, n = keyMembers.Count; i < n; i++)
            {
                int ordinal = currentValues.GetOrdinal(keyMembers[i].Name);
                if (currentValues.IsDBNull(ordinal))
                {
                    hasNullValue = true;
                    break;
                }
                else
                {
                    keyValues[i] = currentValues.GetValue(ordinal);
                }
            }

            if (hasNullValue)
            {
                return;
            }
            else
            {
                valueKey = keyValues.Length == 1
                    ? new EntityKey(addedEntry.EntitySet, keyValues[0])
                    : new EntityKey(addedEntry.EntitySet, keyValues);
            }

            if (_valueKeyToTempKey.ContainsKey(valueKey))
            {
                // null indicates that there are collisions on key values
                _valueKeyToTempKey[valueKey] = null;
            }
            else
            {
                _valueKeyToTempKey.Add(valueKey, tempKey);
            }
        }
                internal DirectionalRelationship(EntityKey toEntityKey, AssociationEndMember fromEnd, AssociationEndMember toEnd, AssociationSet associationSet, IEntityStateEntry stateEntry)
                {
                    ToEntityKey    = EntityUtil.CheckArgumentNull(toEntityKey, "toEntityKey");
                    FromEnd        = EntityUtil.CheckArgumentNull(fromEnd, "fromEnd");
                    ToEnd          = EntityUtil.CheckArgumentNull(toEnd, "toEnd");
                    AssociationSet = EntityUtil.CheckArgumentNull(associationSet, "associationSet");
                    StateEntry     = EntityUtil.CheckArgumentNull(stateEntry, "stateEntry");
                    _equivalenceSetLinkedListNext = this;

                    _hashCode = toEntityKey.GetHashCode() ^
                                fromEnd.GetHashCode() ^
                                toEnd.GetHashCode() ^
                                associationSet.GetHashCode();
                }
Exemple #20
0
        private PropagatorResult CreateSimpleResult(
            IEntityStateEntry stateEntry, IExtendedDataRecord record, MemberInformation memberInformation,
            int identifier, bool isModified, int recordOrdinal, object value)
        {
            var updatableRecord = record as CurrentValueRecord;

            // construct flags for the value, which is needed for complex type and simple members
            var flags = memberInformation.Flags;

            if (!isModified)
            {
                flags |= PropagatorFlags.Preserve;
            }
            if (PropagatorResult.NullIdentifier != identifier)
            {
                // construct a key member
                PropagatorResult result;
                if ((memberInformation.IsServerGenerated || memberInformation.IsForeignKeyMember) &&
                    null != updatableRecord)
                {
                    result = PropagatorResult.CreateServerGenKeyValue(flags, value, stateEntry, identifier, recordOrdinal);
                }
                else
                {
                    result = PropagatorResult.CreateKeyValue(flags, value, stateEntry, identifier);
                }

                // we register the entity as the "owner" of an identity so that back-propagation can succeed
                // (keys can only be back-propagated to entities, not association ends). It also allows us
                // to walk to the entity state entry in case of exceptions, since the state entry propagated
                // through the stack may be eliminated in a project above a join.
                m_translator.KeyManager.RegisterIdentifierOwner(result);

                return(result);
            }
            else
            {
                if ((memberInformation.IsServerGenerated || memberInformation.IsForeignKeyMember) &&
                    null != updatableRecord)
                {
                    // note: we only produce a server gen result when
                    return(PropagatorResult.CreateServerGenSimpleValue(flags, value, updatableRecord, recordOrdinal));
                }
                else
                {
                    return(PropagatorResult.CreateSimpleValue(flags, value));
                }
            }
        }
Exemple #21
0
 internal static void ValidateNecessaryModificationFunctionMapping(
     ModificationFunctionMapping mapping,
     string currentState,
     IEntityStateEntry stateEntry,
     string type,
     string typeName)
 {
     if (mapping == null)
     {
         throw new UpdateException(Strings.Update_MissingFunctionMapping((object)currentState, (object)type, (object)typeName), (Exception)null, new List <IEntityStateEntry>()
         {
             stateEntry
         }.Cast <ObjectStateEntry>().Distinct <ObjectStateEntry>());
     }
 }
        internal void AddReferentialConstraint(
            IEntityStateEntry dependentStateEntry,
            int dependentIdentifier,
            int principalIdentifier)
        {
            KeyManager.IdentifierInfo identifier = this._identifiers[dependentIdentifier];
            if (dependentIdentifier != principalIdentifier)
            {
                this.AssociateNodes(dependentIdentifier, principalIdentifier);
                KeyManager.LinkedList <int> .Add(ref identifier.References, principalIdentifier);

                KeyManager.LinkedList <int> .Add(ref this._identifiers[principalIdentifier].ReferencedBy, dependentIdentifier);
            }
            KeyManager.LinkedList <IEntityStateEntry> .Add(ref identifier.DependentStateEntries, dependentStateEntry);
        }
Exemple #23
0
 internal static void ValidateNecessaryModificationFunctionMapping(
     StorageModificationFunctionMapping mapping, string currentState,
     IEntityStateEntry stateEntry, string type, string typeName)
 {
     if (null == mapping)
     {
         throw new UpdateException(
                   Strings.Update_MissingFunctionMapping(currentState, type, typeName),
                   null,
                   new List <IEntityStateEntry>
         {
             stateEntry
         }.Cast <ObjectStateEntry>().Distinct());
     }
 }
Exemple #24
0
        // Note that this is called only for association ends. Entities have key values inline.
        private PropagatorResult CreateEntityKeyResult(IEntityStateEntry stateEntry, EntityKey entityKey)
        {
            // get metadata for key
            var entityType = entityKey.GetEntitySet(m_translator.MetadataWorkspace).ElementType;
            var keyRowType = entityType.GetKeyRowType();

            var keyMetadata    = m_translator.GetExtractorMetadata(stateEntry.EntitySet, keyRowType);
            var keyMemberCount = keyRowType.Properties.Count;
            var keyValues      = new PropagatorResult[keyMemberCount];

            for (var ordinal = 0; ordinal < keyRowType.Properties.Count; ordinal++)
            {
                EdmMember keyMember = keyRowType.Properties[ordinal];
                // retrieve information about this key value
                var keyMemberInformation = keyMetadata.m_memberMap[ordinal];

                var keyIdentifier = m_translator.KeyManager.GetKeyIdentifierForMemberOffset(entityKey, ordinal, keyRowType.Properties.Count);

                object keyValue = null;
                if (entityKey.IsTemporary)
                {
                    // If the EntityKey is temporary, we need to retrieve the appropriate
                    // key value from the entity itself (or in this case, the IEntityStateEntry).
                    var entityEntry = stateEntry.StateManager.GetEntityStateEntry(entityKey);
                    Debug.Assert(
                        entityEntry.State == EntityState.Added,
                        "The corresponding entry for a temp EntityKey should be in the Added State.");
                    keyValue = entityEntry.CurrentValues[keyMember.Name];
                }
                else
                {
                    // Otherwise, we extract the value from within the EntityKey.
                    keyValue = entityKey.FindValueByName(keyMember.Name);
                }
                Debug.Assert(keyValue != null, "keyValue should've been retrieved.");

                // construct propagator result
                keyValues[ordinal] = PropagatorResult.CreateKeyValue(
                    keyMemberInformation.Flags,
                    keyValue,
                    stateEntry,
                    keyIdentifier);

                // see UpdateTranslator.Identifiers for information on key identifiers and ordinals
            }

            return(PropagatorResult.CreateStructuralValue(keyValues, keyMetadata.m_type, false));
        }
Exemple #25
0
        /// <summary>
        /// Converts a record to a propagator result
        /// </summary>
        /// <param name="stateEntry">state manager entry containing the record</param>
        /// <param name="isModified">Indicates whether the root element is modified (i.e., whether the type has changed)</param>
        /// <param name="record">Record to convert</param>
        /// <param name="useCurrentValues">Indicates whether we are retrieving current or original values.</param>
        /// <param name="translator">Translator for session context; registers new metadata for the record type if none
        /// exists</param>
        /// <param name="modifiedPropertiesBehavior">Indicates how to determine whether a property is modified.</param>
        /// <returns>Result corresponding to the given record</returns>
        internal static PropagatorResult ExtractResultFromRecord(IEntityStateEntry stateEntry, bool isModified, IExtendedDataRecord record,
                                                                 bool useCurrentValues, UpdateTranslator translator, ModifiedPropertiesBehavior modifiedPropertiesBehavior)
        {
            StructuralType    structuralType = (StructuralType)record.DataRecordInfo.RecordType.EdmType;
            ExtractorMetadata metadata       = translator.GetExtractorMetadata(stateEntry.EntitySet, structuralType);
            EntityKey         key            = stateEntry.EntityKey;

            PropagatorResult[] nestedValues = new PropagatorResult[record.FieldCount];
            for (int ordinal = 0; ordinal < nestedValues.Length; ordinal++)
            {
                nestedValues[ordinal] = metadata.RetrieveMember(stateEntry, record, useCurrentValues, key,
                                                                ordinal, modifiedPropertiesBehavior);
            }

            return(PropagatorResult.CreateStructuralValue(nestedValues, structuralType, isModified));
        }
        public void VmShouldReturnChangesOnlyForProductModel()
        {
            var model = new ProductModel
            {
                Name        = "test",
                Description = "test",
                Id          = Guid.NewGuid(),
                Price       = 10
            };
            var viewModel = GetViewModel <ProductEditorViewModel>();

            viewModel.InitializeEntity(model, false);
            IEntityStateEntry entityStateEntry = viewModel.ApplyChanges().Single();

            Assert.AreEqual(entityStateEntry.Entity, model);
        }
        /// <summary>
        ///     Initializes a new instance of the <see cref = "InternalEntityEntry" /> class for an
        ///     entity which may or may not be attached to the context.
        /// </summary>
        /// <param name = "internalContext">The internal context.</param>
        /// <param name = "entity">The entity.</param>
        public InternalEntityEntry(InternalContext internalContext, object entity)
        {
            //Contract.Requires(internalContext != null);
            //Contract.Requires(entity != null);

            _internalContext = internalContext;
            _entity = entity;
            _entityType = ObjectContextTypeCache.GetObjectType(_entity.GetType());

            _stateEntry = _internalContext.GetStateEntry(entity);
            if (_stateEntry == null)
            {
                // This will cause the context and model to be initialized and will throw an exception
                // if the entity type is not part of the model.
                _internalContext.Set(_entityType).InternalSet.Initialize();
            }
        }
        // <summary>
        // Initializes a new instance of the <see cref="InternalEntityEntry" /> class for an
        // entity which may or may not be attached to the context.
        // </summary>
        // <param name="internalContext"> The internal context. </param>
        // <param name="entity"> The entity. </param>
        public InternalEntityEntry(InternalContext internalContext, object entity)
        {
            DebugCheck.NotNull(internalContext);
            DebugCheck.NotNull(entity);

            _internalContext = internalContext;
            _entity          = entity;
            _entityType      = ObjectContextTypeCache.GetObjectType(_entity.GetType());

            _stateEntry = _internalContext.GetStateEntry(entity);
            if (_stateEntry == null)
            {
                // This will cause the context and model to be initialized and will throw an exception
                // if the entity type is not part of the model.
                _internalContext.Set(_entityType).InternalSet.Initialize();
            }
        }
        private PropagatorResult CreateEntityKeyResult(
            IEntityStateEntry stateEntry,
            EntityKey entityKey)
        {
            RowType           keyRowType        = entityKey.GetEntitySet(this.m_translator.MetadataWorkspace).ElementType.GetKeyRowType();
            ExtractorMetadata extractorMetadata = this.m_translator.GetExtractorMetadata(stateEntry.EntitySet, (StructuralType)keyRowType);

            PropagatorResult[] values = new PropagatorResult[keyRowType.Properties.Count];
            for (int memberOffset = 0; memberOffset < keyRowType.Properties.Count; ++memberOffset)
            {
                EdmMember property = (EdmMember)keyRowType.Properties[memberOffset];
                ExtractorMetadata.MemberInformation member = extractorMetadata.m_memberMap[memberOffset];
                int    identifierForMemberOffset           = this.m_translator.KeyManager.GetKeyIdentifierForMemberOffset(entityKey, memberOffset, keyRowType.Properties.Count);
                object obj = !entityKey.IsTemporary ? entityKey.FindValueByName(property.Name) : stateEntry.StateManager.GetEntityStateEntry(entityKey).CurrentValues[property.Name];
                values[memberOffset] = PropagatorResult.CreateKeyValue(member.Flags, obj, stateEntry, identifierForMemberOffset);
            }
            return(PropagatorResult.CreateStructuralValue(values, extractorMetadata.m_type, false));
        }
Exemple #30
0
        internal static UpdateException UpdateRelationshipCardinalityConstraintViolation(
            string relationshipSetName,
            int minimumCount,
            int?maximumCount,
            string entitySetName,
            int actualCount,
            string otherEndPluralName,
            IEntityStateEntry stateEntry)
        {
            string str1 = EntityUtil.ConvertCardinalityToString(new int?(minimumCount));
            string str2 = EntityUtil.ConvertCardinalityToString(maximumCount);
            string str3 = EntityUtil.ConvertCardinalityToString(new int?(actualCount));

            if (minimumCount == 1 && str1 == str2)
            {
                return(EntityUtil.Update(Strings.Update_RelationshipCardinalityConstraintViolationSingleValue((object)entitySetName, (object)relationshipSetName, (object)str3, (object)otherEndPluralName, (object)str1), (Exception)null, stateEntry));
            }
            return(EntityUtil.Update(Strings.Update_RelationshipCardinalityConstraintViolation((object)entitySetName, (object)relationshipSetName, (object)str3, (object)otherEndPluralName, (object)str1, (object)str2), (Exception)null, stateEntry));
        }
        internal ExtractedStateEntry(UpdateTranslator translator, IEntityStateEntry stateEntry)
        {
            DebugCheck.NotNull(translator);
            DebugCheck.NotNull(stateEntry);

            State  = stateEntry.State;
            Source = stateEntry;

            switch (stateEntry.State)
            {
            case EntityState.Deleted:
                Original = translator.RecordConverter.ConvertOriginalValuesToPropagatorResult(
                    stateEntry, ModifiedPropertiesBehavior.AllModified);
                Current = null;
                break;

            case EntityState.Unchanged:
                Original = translator.RecordConverter.ConvertOriginalValuesToPropagatorResult(
                    stateEntry, ModifiedPropertiesBehavior.NoneModified);
                Current = translator.RecordConverter.ConvertCurrentValuesToPropagatorResult(
                    stateEntry, ModifiedPropertiesBehavior.NoneModified);
                break;

            case EntityState.Modified:
                Original = translator.RecordConverter.ConvertOriginalValuesToPropagatorResult(
                    stateEntry, ModifiedPropertiesBehavior.SomeModified);
                Current = translator.RecordConverter.ConvertCurrentValuesToPropagatorResult(
                    stateEntry, ModifiedPropertiesBehavior.SomeModified);
                break;

            case EntityState.Added:
                Original = null;
                Current  = translator.RecordConverter.ConvertCurrentValuesToPropagatorResult(
                    stateEntry, ModifiedPropertiesBehavior.AllModified);
                break;

            default:
                Debug.Assert(false, "Unexpected IEntityStateEntry.State for entity " + stateEntry.State);
                Original = null;
                Current  = null;
                break;
            }
        }
Exemple #32
0
 private PropagatorResult ConvertStateEntryToPropagatorResult(
     IEntityStateEntry stateEntry,
     bool useCurrentValues,
     ModifiedPropertiesBehavior modifiedPropertiesBehavior)
 {
     try
     {
         IExtendedDataRecord record = useCurrentValues ? (IExtendedDataRecord)stateEntry.CurrentValues : (IExtendedDataRecord)stateEntry.OriginalValues;
         bool isModified            = false;
         return(ExtractorMetadata.ExtractResultFromRecord(stateEntry, isModified, record, useCurrentValues, this.m_updateTranslator, modifiedPropertiesBehavior));
     }
     catch (Exception ex)
     {
         if (ex.RequiresContext())
         {
             throw EntityUtil.Update(Strings.Update_ErrorLoadingRecord, ex, stateEntry);
         }
         throw;
     }
 }
Exemple #33
0
        /// <summary>
        /// Indicate that the principal identifier controls the value for the dependent identifier.
        /// </summary>
        internal void AddReferentialConstraint(IEntityStateEntry dependentStateEntry, int dependentIdentifier, int principalIdentifier)
        {
            IdentifierInfo dependentInfo = _identifiers[dependentIdentifier];

            // A value is trivially constrained to be itself
            if (dependentIdentifier != principalIdentifier)
            {
                // track these as 'equivalent values'; used to determine canonical identifier for dependency
                // ordering and validation of constraints
                AssociateNodes(dependentIdentifier, principalIdentifier);

                // remember the constraint
                LinkedList <int> .Add(ref dependentInfo.References, principalIdentifier);

                IdentifierInfo principalInfo = _identifiers[principalIdentifier];
                LinkedList <int> .Add(ref principalInfo.ReferencedBy, dependentIdentifier);
            }

            LinkedList <IEntityStateEntry> .Add(ref dependentInfo.DependentStateEntries, dependentStateEntry);
        }
Exemple #34
0
        internal ExtractedStateEntry(UpdateTranslator translator, IEntityStateEntry stateEntry)
        {
            Debug.Assert(null != stateEntry, "stateEntry must not be null");
            this.State  = stateEntry.State;
            this.Source = stateEntry;

            switch (stateEntry.State)
            {
            case EntityState.Deleted:
                this.Original = translator.RecordConverter.ConvertOriginalValuesToPropagatorResult(
                    stateEntry, ModifiedPropertiesBehavior.AllModified);
                this.Current = null;
                break;

            case EntityState.Unchanged:
                this.Original = translator.RecordConverter.ConvertOriginalValuesToPropagatorResult(
                    stateEntry, ModifiedPropertiesBehavior.NoneModified);
                this.Current = translator.RecordConverter.ConvertCurrentValuesToPropagatorResult(
                    stateEntry, ModifiedPropertiesBehavior.NoneModified);
                break;

            case EntityState.Modified:
                this.Original = translator.RecordConverter.ConvertOriginalValuesToPropagatorResult(
                    stateEntry, ModifiedPropertiesBehavior.SomeModified);
                this.Current = translator.RecordConverter.ConvertCurrentValuesToPropagatorResult(
                    stateEntry, ModifiedPropertiesBehavior.SomeModified);
                break;

            case EntityState.Added:
                this.Original = null;
                this.Current  = translator.RecordConverter.ConvertCurrentValuesToPropagatorResult(
                    stateEntry, ModifiedPropertiesBehavior.AllModified);
                break;

            default:
                Debug.Fail("unexpected IEntityStateEntry.State for entity " + stateEntry.State);
                this.Original = null;
                this.Current  = null;
                break;
            }
        }
        private PropagatorResult ConvertStateEntryToPropagatorResult(IEntityStateEntry stateEntry, bool useCurrentValues, ModifiedPropertiesBehavior modifiedPropertiesBehavior)
        {
            try
            {
                EntityUtil.CheckArgumentNull(stateEntry, "stateEntry");
                IExtendedDataRecord record = useCurrentValues
                    ? EntityUtil.CheckArgumentNull(stateEntry.CurrentValues as IExtendedDataRecord, "stateEntry.CurrentValues")
                    : EntityUtil.CheckArgumentNull(stateEntry.OriginalValues as IExtendedDataRecord, "stateEntry.OriginalValues");

                bool isModified = false; // the root of the state entry is unchanged because the type is static
                return ExtractorMetadata.ExtractResultFromRecord(stateEntry, isModified, record, useCurrentValues, m_updateTranslator, modifiedPropertiesBehavior);
            }
            catch (Exception e)
            {
                if (UpdateTranslator.RequiresContext(e))
                {
                    throw EntityUtil.Update(Strings.Update_ErrorLoadingRecord, e, stateEntry);
                }
                throw;
            }
        }
        internal ExtractedStateEntry(UpdateTranslator translator, IEntityStateEntry stateEntry)
        {
            DebugCheck.NotNull(translator);
            DebugCheck.NotNull(stateEntry);

            State = stateEntry.State;
            Source = stateEntry;

            switch (stateEntry.State)
            {
                case EntityState.Deleted:
                    Original = translator.RecordConverter.ConvertOriginalValuesToPropagatorResult(
                        stateEntry, ModifiedPropertiesBehavior.AllModified);
                    Current = null;
                    break;
                case EntityState.Unchanged:
                    Original = translator.RecordConverter.ConvertOriginalValuesToPropagatorResult(
                        stateEntry, ModifiedPropertiesBehavior.NoneModified);
                    Current = translator.RecordConverter.ConvertCurrentValuesToPropagatorResult(
                        stateEntry, ModifiedPropertiesBehavior.NoneModified);
                    break;
                case EntityState.Modified:
                    Original = translator.RecordConverter.ConvertOriginalValuesToPropagatorResult(
                        stateEntry, ModifiedPropertiesBehavior.SomeModified);
                    Current = translator.RecordConverter.ConvertCurrentValuesToPropagatorResult(
                        stateEntry, ModifiedPropertiesBehavior.SomeModified);
                    break;
                case EntityState.Added:
                    Original = null;
                    Current = translator.RecordConverter.ConvertCurrentValuesToPropagatorResult(
                        stateEntry, ModifiedPropertiesBehavior.AllModified);
                    break;
                default:
                    Debug.Assert(false, "Unexpected IEntityStateEntry.State for entity " + stateEntry.State);
                    Original = null;
                    Current = null;
                    break;
            }
        }
        internal ExtractedStateEntry(UpdateTranslator translator, IEntityStateEntry stateEntry)
        {
            Debug.Assert(null != stateEntry, "stateEntry must not be null");
            this.State = stateEntry.State;
            this.Source = stateEntry;

            switch (stateEntry.State)
            {
                case EntityState.Deleted:
                    this.Original = translator.RecordConverter.ConvertOriginalValuesToPropagatorResult(
                        stateEntry, ModifiedPropertiesBehavior.AllModified);
                    this.Current = null;
                    break;
                case EntityState.Unchanged:
                    this.Original = translator.RecordConverter.ConvertOriginalValuesToPropagatorResult(
                        stateEntry, ModifiedPropertiesBehavior.NoneModified);
                    this.Current = translator.RecordConverter.ConvertCurrentValuesToPropagatorResult(
                        stateEntry, ModifiedPropertiesBehavior.NoneModified);
                    break;
                case EntityState.Modified:
                    this.Original = translator.RecordConverter.ConvertOriginalValuesToPropagatorResult(
                        stateEntry, ModifiedPropertiesBehavior.SomeModified);
                    this.Current = translator.RecordConverter.ConvertCurrentValuesToPropagatorResult(
                        stateEntry, ModifiedPropertiesBehavior.SomeModified);
                    break;
                case EntityState.Added:
                    this.Original = null;
                    this.Current = translator.RecordConverter.ConvertCurrentValuesToPropagatorResult(
                        stateEntry, ModifiedPropertiesBehavior.AllModified);
                    break;
                default:
                    Debug.Fail("unexpected IEntityStateEntry.State for entity " + stateEntry.State);
                    this.Original = null;
                    this.Current = null;
                    break;
            }
        }
        private PropagatorResult ConvertStateEntryToPropagatorResult(
            IEntityStateEntry stateEntry, bool useCurrentValues, ModifiedPropertiesBehavior modifiedPropertiesBehavior)
        {
            Contract.Requires(stateEntry != null);

            try
            {
                var record = useCurrentValues
                                 ? stateEntry.CurrentValues
                                 : (IExtendedDataRecord)stateEntry.OriginalValues;

                var isModified = false; // the root of the state entry is unchanged because the type is static
                return ExtractorMetadata.ExtractResultFromRecord(
                    stateEntry, isModified, record, useCurrentValues, m_updateTranslator, modifiedPropertiesBehavior);
            }
            catch (Exception e)
            {
                if (e.RequiresContext())
                {
                    throw EntityUtil.Update(Strings.Update_ErrorLoadingRecord, e, stateEntry);
                }
                throw;
            }
        }
        /// <summary>
        /// Converts a record to a propagator result
        /// </summary>
        /// <param name="stateEntry">state manager entry containing the record</param>
        /// <param name="isModified">Indicates whether the root element is modified (i.e., whether the type has changed)</param>
        /// <param name="record">Record to convert</param>
        /// <param name="useCurrentValues">Indicates whether we are retrieving current or original values.</param>
        /// <param name="translator">Translator for session context; registers new metadata for the record type if none
        /// exists</param>
        /// <param name="modifiedPropertiesBehavior">Indicates how to determine whether a property is modified.</param>
        /// <returns>Result corresponding to the given record</returns>
        internal static PropagatorResult ExtractResultFromRecord(
            IEntityStateEntry stateEntry, bool isModified, IExtendedDataRecord record,
            bool useCurrentValues, UpdateTranslator translator, ModifiedPropertiesBehavior modifiedPropertiesBehavior)
        {
            var structuralType = (StructuralType)record.DataRecordInfo.RecordType.EdmType;
            var metadata = translator.GetExtractorMetadata(stateEntry.EntitySet, structuralType);
            var key = stateEntry.EntityKey;

            var nestedValues = new PropagatorResult[record.FieldCount];
            for (var ordinal = 0; ordinal < nestedValues.Length; ordinal++)
            {
                nestedValues[ordinal] = metadata.RetrieveMember(
                    stateEntry, record, useCurrentValues, key,
                    ordinal, modifiedPropertiesBehavior);
            }

            return PropagatorResult.CreateStructuralValue(nestedValues, structuralType, isModified);
        }
        private void ValidateRecord(EntitySetBase extent, IExtendedDataRecord record, IEntityStateEntry entry)
        {
            Debug.Assert(null != extent, "must be verified by caller");

            DataRecordInfo recordInfo;
            if ((null == record) ||
                (null == (recordInfo = record.DataRecordInfo)) ||
                (null == recordInfo.RecordType))
            {
                throw EntityUtil.InternalError(EntityUtil.InternalErrorCode.InvalidStateEntry, 2);
            }

            VerifyExtent(MetadataWorkspace, extent);

            // additional validation happens lazily as values are loaded from the record
        }
        /// <summary>
        /// Registers any referential constraints contained in the state entry (so that
        /// constrained members have the same identifier values). Only processes relationships
        /// with referential constraints defined.
        /// </summary>
        /// <param name="stateEntry">State entry</param>
        internal void RegisterReferentialConstraints(IEntityStateEntry stateEntry)
        {
            if (stateEntry.IsRelationship)
            {
                AssociationSet associationSet = (AssociationSet)stateEntry.EntitySet;
                if (0 < associationSet.ElementType.ReferentialConstraints.Count)
                {
                    DbDataRecord record = stateEntry.State == EntityState.Added ?
                        (DbDataRecord)stateEntry.CurrentValues : stateEntry.OriginalValues;
                    foreach (ReferentialConstraint constraint in associationSet.ElementType.ReferentialConstraints)
                    {
                        // retrieve keys at the ends
                        EntityKey principalKey = (EntityKey)record[constraint.FromRole.Name];
                        EntityKey dependentKey = (EntityKey)record[constraint.ToRole.Name];

                        // associate keys, where the from side 'owns' the to side
                        using (ReadOnlyMetadataCollection<EdmProperty>.Enumerator principalPropertyEnum = constraint.FromProperties.GetEnumerator())
                        using (ReadOnlyMetadataCollection<EdmProperty>.Enumerator dependentPropertyEnum = constraint.ToProperties.GetEnumerator())
                        {
                            while (principalPropertyEnum.MoveNext() && dependentPropertyEnum.MoveNext())
                            {
                                int principalKeyMemberCount;
                                int dependentKeyMemberCount;

                                // get offsets for from and to key properties
                                int principalOffset = GetKeyMemberOffset(constraint.FromRole, principalPropertyEnum.Current,
                                    out principalKeyMemberCount);
                                int dependentOffset = GetKeyMemberOffset(constraint.ToRole, dependentPropertyEnum.Current,
                                    out dependentKeyMemberCount);

                                int principalIdentifier = this.KeyManager.GetKeyIdentifierForMemberOffset(principalKey, principalOffset, principalKeyMemberCount);
                                int dependentIdentifier = this.KeyManager.GetKeyIdentifierForMemberOffset(dependentKey, dependentOffset, dependentKeyMemberCount);

                                // register equivalence of identifiers
                                this.KeyManager.AddReferentialConstraint(stateEntry, dependentIdentifier, principalIdentifier);
                            }
                        }
                    }
                }
            }
            else if (!stateEntry.IsKeyEntry)
            {
                if (stateEntry.State == EntityState.Added || stateEntry.State == EntityState.Modified)
                {
                    RegisterEntityReferentialConstraints(stateEntry, true);
                }
                if (stateEntry.State == EntityState.Deleted || stateEntry.State == EntityState.Modified)
                {
                    RegisterEntityReferentialConstraints(stateEntry, false);
                }
            }
        }
        public void ApplyChangesInternalShouldBeUsedAsMainEntityAndChangesMethod()
        {
            bool isInvoked = false;
            StateManager.CreateSnapshot = o => new EntitySnapshotMock();
            var entries = new IEntityStateEntry[0];
            var entity = new object();
            var viewModel = GetViewModel<EditableViewModelMock>();
            viewModel.ApplyChangesInternalDelegate = () =>
            {
                isInvoked = true;
                return new ApplyChangesClass
                {
                    Entity = entity,
                    EntityStateEntries = entries
                };
            };

            viewModel.InitializeEntity(new object(), true);
            viewModel.ApplyChanges().ShouldEqual(entries);
            viewModel.Entity.ShouldEqual(entity);
            isInvoked.ShouldBeTrue();
        }
        /// <summary>
        /// Requires: record must have correct type for this metadata instance.
        /// Populates a new <see cref="PropagatorResult"/> object representing a member of a record matching the 
        /// type of this extractor. Given a record and a member, this method wraps the value of the member
        /// in a PropagatorResult. This operation can be performed efficiently by this class, which knows
        /// important stuff about the type being extracted.
        /// </summary>
        /// <param name="stateEntry">state manager entry containing value (used for error reporting)</param>
        /// <param name="record">Record containing value (used to find the actual value)</param>
        /// <param name="currentValues">Indicates whether we are reading current or original values.</param>
        /// <param name="key">Entity key for the state entry. Must be set for entity records.</param>
        /// <param name="ordinal">Ordinal of Member for which to retrieve a value.</param>
        /// modified (must be ordinally aligned with the type). Null indicates all members are modified.</param>
        /// <param name="modifiedPropertiesBehavior">Indicates how to determine whether a property is modified.</param>
        /// <returns>Propagator result describing this member value.</returns>
        internal PropagatorResult RetrieveMember(
            IEntityStateEntry stateEntry, IExtendedDataRecord record, bool useCurrentValues,
            EntityKey key, int ordinal, ModifiedPropertiesBehavior modifiedPropertiesBehavior)
        {
            var memberInformation = m_memberMap[ordinal];

            // get identifier value
            int identifier;
            if (memberInformation.IsKeyMember)
            {
                // retrieve identifier for this key member
                Debug.Assert(
                    null != (object)key, "entities must have keys, and only entity members are marked IsKeyMember by " +
                                         "the metadata wrapper");
                var keyOrdinal = memberInformation.EntityKeyOrdinal.Value;
                identifier = m_translator.KeyManager.GetKeyIdentifierForMemberOffset(key, keyOrdinal, ((EntityType)m_type).KeyMembers.Count);
            }
            else if (memberInformation.IsForeignKeyMember)
            {
                identifier = m_translator.KeyManager.GetKeyIdentifierForMember(key, record.GetName(ordinal), useCurrentValues);
            }
            else
            {
                identifier = PropagatorResult.NullIdentifier;
            }

            // determine if the member is modified
            var isModified = modifiedPropertiesBehavior == ModifiedPropertiesBehavior.AllModified ||
                             (modifiedPropertiesBehavior == ModifiedPropertiesBehavior.SomeModified &&
                              stateEntry.ModifiedProperties != null &&
                              stateEntry.ModifiedProperties[memberInformation.Ordinal]);

            // determine member value
            Debug.Assert(record.GetName(ordinal) == memberInformation.Member.Name, "expect record to present properties in metadata order");
            if (memberInformation.CheckIsNotNull
                && record.IsDBNull(ordinal))
            {
                throw EntityUtil.Update(Strings.Update_NullValue(record.GetName(ordinal)), null, stateEntry);
            }
            var value = record.GetValue(ordinal);

            // determine what kind of member this is

            // entityKey (association end)
            var entityKey = value as EntityKey;
            if (null != (object)entityKey)
            {
                return CreateEntityKeyResult(stateEntry, entityKey);
            }

            // record (nested complex type)
            var nestedRecord = value as IExtendedDataRecord;
            if (null != nestedRecord)
            {
                // for structural types, we track whether the entire complex type value is modified or not
                var nestedModifiedPropertiesBehavior = isModified
                                                           ? ModifiedPropertiesBehavior.AllModified
                                                           : ModifiedPropertiesBehavior.NoneModified;
                var translator = m_translator;

                return ExtractResultFromRecord(
                    stateEntry, isModified, nestedRecord, useCurrentValues, translator, nestedModifiedPropertiesBehavior);
            }

            // simple value (column/property value)
            return CreateSimpleResult(stateEntry, record, memberInformation, identifier, isModified, ordinal, value);
        }
 internal static PropagatorResult CreateServerGenKeyValue(
     PropagatorFlags flags, object value, IEntityStateEntry stateEntry, int identifier, int recordOrdinal)
 {
     return new ServerGenKeyValue(flags, value, stateEntry, identifier, recordOrdinal, null);
 }
            internal KeyValue(PropagatorFlags flags, object value, IEntityStateEntry stateEntry, int identifier, KeyValue next)
                : base(flags, value)
            {
                Debug.Assert(null != stateEntry);

                m_stateEntry = stateEntry;
                m_identifier = identifier;
                m_next = next;
            }
 internal static PropagatorResult CreateKeyValue(PropagatorFlags flags, object value, IEntityStateEntry stateEntry, int identifier)
 {
     return new KeyValue(flags, value, stateEntry, identifier, null);
 }
        /// <summary>
        /// Validates and tracks a state entry being processed by this translator.
        /// </summary>
        /// <param name="stateEntry"></param>
        private void ValidateAndRegisterStateEntry(IEntityStateEntry stateEntry)
        {
            EntityUtil.CheckArgumentNull(stateEntry, "stateEntry");

            EntitySetBase extent = stateEntry.EntitySet;
            if (null == extent) 
            {
                throw EntityUtil.InternalError(EntityUtil.InternalErrorCode.InvalidStateEntry, 1);
            }

            // Determine the key. May be null if the state entry does not represent an entity.
            EntityKey entityKey = stateEntry.EntityKey;
            IExtendedDataRecord record = null;

            // verify the structure of the entry values
            if (0 != ((EntityState.Added | EntityState.Modified | EntityState.Unchanged) & stateEntry.State))
            {
                // added, modified and unchanged entries have current values
                record = (IExtendedDataRecord)stateEntry.CurrentValues;
                ValidateRecord(extent, record, stateEntry);
            }
            if (0 != ((EntityState.Modified | EntityState.Deleted | EntityState.Unchanged) & stateEntry.State))
            {
                // deleted, modified and unchanged entries have original values
                record = (IExtendedDataRecord)stateEntry.OriginalValues;
                ValidateRecord(extent, record, stateEntry);
            }
            Debug.Assert(null != record, "every state entry must contain a record");

            // check for required ends of relationships
            AssociationSet associationSet = extent as AssociationSet;
            if (null != associationSet)
            {
                AssociationSetMetadata associationSetMetadata = m_viewLoader.GetAssociationSetMetadata(associationSet, m_metadataWorkspace);

                if (associationSetMetadata.HasEnds)
                {
                    foreach (FieldMetadata field in record.DataRecordInfo.FieldMetadata)
                    {
                        // ends of relationship record must be EntityKeys
                        EntityKey end = (EntityKey)record.GetValue(field.Ordinal);

                        // ends of relationships must have AssociationEndMember metadata
                        AssociationEndMember endMetadata = (AssociationEndMember)field.FieldType;

                        if (associationSetMetadata.RequiredEnds.Contains(endMetadata))
                        {
                            if (!m_requiredEntities.ContainsKey(end))
                            {
                                m_requiredEntities.Add(end, associationSet);
                            }
                        }

                        else if (associationSetMetadata.OptionalEnds.Contains(endMetadata))
                        {
                            AddValidAncillaryKey(end, m_optionalEntities);
                        }

                        else if (associationSetMetadata.IncludedValueEnds.Contains(endMetadata))
                        {
                            AddValidAncillaryKey(end, m_includedValueEntities);
                        }
                    }
                }

                // register relationship with validator
                m_constraintValidator.RegisterAssociation(associationSet, record, stateEntry);
            }
            else
            {
                // register entity with validator
                m_constraintValidator.RegisterEntity(stateEntry);
            }

            // add to the list of entries being tracked
            m_stateEntries.Add(stateEntry);
            if (null != (object)entityKey) { m_knownEntityKeys.Add(entityKey); }
        }
        public void GetChangesShouldBeUsedAsMainChanges()
        {
            bool isInvoked = false;
            bool isInvokedChangesApplied = false;
            StateManager.CreateSnapshot = o => new EntitySnapshotMock();
            var entries = new IEntityStateEntry[0];
            var entity = new object();

            var viewModel = GetViewModel<EditableViewModelMock>();
            viewModel.GetChangesDelegate = o =>
            {
                isInvoked = true;
                o.ShouldEqual(entity);
                return entries;
            };
            viewModel.OnChangesAppliedDelegate = list =>
            {
                list.ShouldEqual(entries);
                isInvokedChangesApplied = true;
            };

            viewModel.InitializeEntity(entity, false);
            viewModel.ApplyChanges().ShouldEqual(entries);
            isInvoked.ShouldBeTrue();
            isInvokedChangesApplied.ShouldBeTrue();
        }
        private PropagatorResult CreateSimpleResult(
            IEntityStateEntry stateEntry, IExtendedDataRecord record, MemberInformation memberInformation,
            int identifier, bool isModified, int recordOrdinal, object value)
        {
            var updatableRecord = record as CurrentValueRecord;

            // construct flags for the value, which is needed for complex type and simple members
            var flags = memberInformation.Flags;
            if (!isModified)
            {
                flags |= PropagatorFlags.Preserve;
            }
            if (PropagatorResult.NullIdentifier != identifier)
            {
                // construct a key member
                PropagatorResult result;
                if ((memberInformation.IsServerGenerated || memberInformation.IsForeignKeyMember)
                    && null != updatableRecord)
                {
                    result = PropagatorResult.CreateServerGenKeyValue(flags, value, stateEntry, identifier, recordOrdinal);
                }
                else
                {
                    result = PropagatorResult.CreateKeyValue(flags, value, stateEntry, identifier);
                }

                // we register the entity as the "owner" of an identity so that back-propagation can succeed
                // (keys can only be back-propagated to entities, not association ends). It also allows us
                // to walk to the entity state entry in case of exceptions, since the state entry propagated
                // through the stack may be eliminated in a project above a join.
                m_translator.KeyManager.RegisterIdentifierOwner(result);

                return result;
            }
            else
            {
                if ((memberInformation.IsServerGenerated || memberInformation.IsForeignKeyMember)
                    && null != updatableRecord)
                {
                    // note: we only produce a server gen result when 
                    return PropagatorResult.CreateServerGenSimpleValue(flags, value, updatableRecord, recordOrdinal);
                }
                else
                {
                    return PropagatorResult.CreateSimpleValue(flags, value);
                }
            }
        }
        // Note that this is called only for association ends. Entities have key values inline.
        private PropagatorResult CreateEntityKeyResult(IEntityStateEntry stateEntry, EntityKey entityKey)
        {
            // get metadata for key
            var entityType = entityKey.GetEntitySet(m_translator.MetadataWorkspace).ElementType;
            var keyRowType = entityType.GetKeyRowType();

            var keyMetadata = m_translator.GetExtractorMetadata(stateEntry.EntitySet, keyRowType);
            var keyMemberCount = keyRowType.Properties.Count;
            var keyValues = new PropagatorResult[keyMemberCount];

            for (var ordinal = 0; ordinal < keyRowType.Properties.Count; ordinal++)
            {
                EdmMember keyMember = keyRowType.Properties[ordinal];
                // retrieve information about this key value
                var keyMemberInformation = keyMetadata.m_memberMap[ordinal];

                var keyIdentifier = m_translator.KeyManager.GetKeyIdentifierForMemberOffset(entityKey, ordinal, keyRowType.Properties.Count);

                object keyValue = null;
                if (entityKey.IsTemporary)
                {
                    // If the EntityKey is temporary, we need to retrieve the appropriate
                    // key value from the entity itself (or in this case, the IEntityStateEntry).
                    var entityEntry = stateEntry.StateManager.GetEntityStateEntry(entityKey);
                    Debug.Assert(
                        entityEntry.State == EntityState.Added,
                        "The corresponding entry for a temp EntityKey should be in the Added State.");
                    keyValue = entityEntry.CurrentValues[keyMember.Name];
                }
                else
                {
                    // Otherwise, we extract the value from within the EntityKey.
                    keyValue = entityKey.FindValueByName(keyMember.Name);
                }
                Debug.Assert(keyValue != null, "keyValue should've been retrieved.");

                // construct propagator result
                keyValues[ordinal] = PropagatorResult.CreateKeyValue(
                    keyMemberInformation.Flags,
                    keyValue,
                    stateEntry,
                    keyIdentifier);

                // see UpdateTranslator.Identifiers for information on key identifiers and ordinals
            }

            return PropagatorResult.CreateStructuralValue(keyValues, keyMetadata.m_type, false);
        }
 internal ServerGenKeyValue(
     PropagatorFlags flags, object value, IEntityStateEntry stateEntry, int identifier, int recordOrdinal, KeyValue next)
     : base(flags, value, stateEntry, identifier, next)
 {
     m_recordOrdinal = recordOrdinal;
 }
 /// <summary>
 /// Converts current values in a state entry to a DbNewInstanceExpression. The record must be either an entity or 
 /// a relationship set instance.
 /// </summary>
 /// <remarks>
 /// This method is not thread safe.
 /// </remarks>
 /// <param name="stateEntry">Gets state entry this record is associated with.</param>
 /// <param name="modifiedPropertiesBehavior">Indicates how to determine whether a property is modified.</param>
 /// <returns>New instance expression.</returns>
 internal PropagatorResult ConvertCurrentValuesToPropagatorResult(IEntityStateEntry stateEntry, ModifiedPropertiesBehavior modifiedPropertiesBehavior)
 {
     return ConvertStateEntryToPropagatorResult(stateEntry, useCurrentValues: true, modifiedPropertiesBehavior: modifiedPropertiesBehavior);
 }
        private void RegisterEntityReferentialConstraints(IEntityStateEntry stateEntry, bool currentValues)
        {
            IExtendedDataRecord record = currentValues
                ? (IExtendedDataRecord)stateEntry.CurrentValues
                : (IExtendedDataRecord)stateEntry.OriginalValues;
            EntitySet entitySet = (EntitySet)stateEntry.EntitySet;
            EntityKey dependentKey = stateEntry.EntityKey;

            foreach (var foreignKey in entitySet.ForeignKeyDependents)
            {
                AssociationSet associationSet = foreignKey.Item1;
                ReferentialConstraint constraint = foreignKey.Item2;
                EntityType dependentType = MetadataHelper.GetEntityTypeForEnd((AssociationEndMember)constraint.ToRole);
                if (dependentType.IsAssignableFrom(record.DataRecordInfo.RecordType.EdmType))
                {
                    EntityKey principalKey = null;

                    // First, check for an explicit reference
                    if (!currentValues || !m_stateManager.TryGetReferenceKey(dependentKey, (AssociationEndMember)constraint.FromRole, out principalKey))
                    {
                        // build a key based on the foreign key values
                        EntityType principalType = MetadataHelper.GetEntityTypeForEnd((AssociationEndMember)constraint.FromRole);
                        bool hasNullValue = false;
                        object[] keyValues = new object[principalType.KeyMembers.Count];
                        for (int i = 0, n = keyValues.Length; i < n; i++)
                        {
                            EdmProperty keyMember = (EdmProperty)principalType.KeyMembers[i];

                            // Find corresponding foreign key value
                            int constraintOrdinal = constraint.FromProperties.IndexOf((EdmProperty)keyMember);
                            int recordOrdinal = record.GetOrdinal(constraint.ToProperties[constraintOrdinal].Name);
                            if (record.IsDBNull(recordOrdinal))
                            {
                                hasNullValue = true;
                                break;
                            }
                            keyValues[i] = record.GetValue(recordOrdinal);
                        }

                        if (!hasNullValue)
                        {
                            EntitySet principalSet = associationSet.AssociationSetEnds[constraint.FromRole.Name].EntitySet;
                            if (1 == keyValues.Length)
                            {
                                principalKey = new EntityKey(principalSet, keyValues[0]);
                            }
                            else
                            {
                                principalKey = new EntityKey(principalSet, keyValues);
                            }
                        }
                    }

                    if (null != principalKey)
                    {
                        // find the right principal key... (first, existing entities; then, added entities; finally, just the key)
                        IEntityStateEntry existingPrincipal;
                        EntityKey tempKey;
                        if (m_stateManager.TryGetEntityStateEntry(principalKey, out existingPrincipal))
                        {
                            // nothing to do. the principal key will resolve to the existing entity
                        }
                        else if (currentValues && this.KeyManager.TryGetTempKey(principalKey, out tempKey))
                        {
                            // if we aren't dealing with current values, we cannot resolve to a temp key (original values
                            // cannot indicate a relationship to an 'added' entity).
                            if (null == tempKey)
                            {
                                throw EntityUtil.Update(Strings.Update_AmbiguousForeignKey(constraint.ToRole.DeclaringType.FullName), null, stateEntry);
                            }
                            else
                            {
                                principalKey = tempKey;
                            }
                        }

                        // pull the principal end into the update pipeline (supports value propagation)
                        AddValidAncillaryKey(principalKey, m_optionalEntities);

                        // associate keys, where the from side 'owns' the to side
                        for (int i = 0, n = constraint.FromProperties.Count; i < n; i++)
                        {
                            var principalProperty = constraint.FromProperties[i];
                            var dependentProperty = constraint.ToProperties[i];

                            int principalKeyMemberCount;

                            // get offsets for from and to key properties
                            int principalOffset = GetKeyMemberOffset(constraint.FromRole, principalProperty, out principalKeyMemberCount);
                            int principalIdentifier = this.KeyManager.GetKeyIdentifierForMemberOffset(principalKey, principalOffset, principalKeyMemberCount);
                            int dependentIdentifier;

                            if (entitySet.ElementType.KeyMembers.Contains(dependentProperty))
                            {
                                int dependentKeyMemberCount;
                                int dependentOffset = GetKeyMemberOffset(constraint.ToRole, dependentProperty,
                                    out dependentKeyMemberCount);
                                dependentIdentifier = this.KeyManager.GetKeyIdentifierForMemberOffset(dependentKey, dependentOffset, dependentKeyMemberCount);
                            }
                            else
                            {
                                dependentIdentifier = this.KeyManager.GetKeyIdentifierForMember(dependentKey, dependentProperty.Name, currentValues);
                            }

                            // don't allow the user to insert or update an entity that refers to a deleted principal
                            if (currentValues && null != existingPrincipal && existingPrincipal.State == EntityState.Deleted &&
                                (stateEntry.State == EntityState.Added || stateEntry.State == EntityState.Modified))
                            {
                                throw EntityUtil.Update(
                                    Strings.Update_InsertingOrUpdatingReferenceToDeletedEntity(associationSet.ElementType.FullName),
                                    null,
                                    stateEntry,
                                    existingPrincipal);
                            }

                            // register equivalence of identifiers
                            this.KeyManager.AddReferentialConstraint(stateEntry, dependentIdentifier, principalIdentifier);
                        }
                    }
                }
            }
        }
        private void LoadStateEntry(IEntityStateEntry stateEntry)
        {
            Debug.Assert(null != stateEntry, "state entry must exist");

            // make sure the state entry doesn't contain invalid data and register it with the
            // update pipeline
            ValidateAndRegisterStateEntry(stateEntry);

            // use data structure internal to the update pipeline instead of the raw state entry
            ExtractedStateEntry extractedStateEntry = new ExtractedStateEntry(this, stateEntry);

            // figure out if this state entry is being handled by a function (stored procedure) or
            // through dynamic SQL
            EntitySetBase extent = stateEntry.EntitySet;
            if (null == m_viewLoader.GetFunctionMappingTranslator(extent, m_metadataWorkspace))
            {
                // if there is no function mapping, register a ChangeNode (used for update
                // propagation and dynamic SQL generation)
                ChangeNode changeNode = GetExtentModifications(extent);
                if (null != extractedStateEntry.Original)
                {
                    changeNode.Deleted.Add(extractedStateEntry.Original);
                }
                if (null != extractedStateEntry.Current)
                {
                    changeNode.Inserted.Add(extractedStateEntry.Current);
                }
            }
            else
            {
                // for function updates, store off the extracted state entry in its entirety
                // (used when producing FunctionUpdateCommands)
                List<ExtractedStateEntry> functionEntries = GetExtentFunctionModifications(extent);
                functionEntries.Add(extractedStateEntry);
            }
        }
            private static void ProcessReferenceCandidate(
                EntityKey source, 
                HashSet<IEntityStateEntry> stateEntries, 
                Dictionary<AssociationEndMember, IEntityStateEntry> currentReferenceEnd, 
                Dictionary<AssociationEndMember, IEntityStateEntry> originalReferenceEnd, 
                AssociationEndMember endMember,
                IEntityStateEntry candidateEntry)
            {
                Func<DbDataRecord, int, EntityKey> getEntityKey = (record, ordinal) => (EntityKey)record[ordinal];
                Action<DbDataRecord, Action<IEntityStateEntry>> findMatch = (record, registerTarget) =>
                {
                    // find the end corresponding to the 'to' end
                    int toOrdinal = record.GetOrdinal(endMember.Name);
                    Debug.Assert(-1 != toOrdinal, "to end of relationship doesn't exist in record");

                    // the 'from' end must be the other end
                    int fromOrdinal = 0 == toOrdinal ? 1 : 0;

                    if (getEntityKey(record, fromOrdinal) == source)
                    {
                        stateEntries.Add(candidateEntry);
                        registerTarget(candidateEntry);
                    }
                };

                switch (candidateEntry.State)
                {
                    case EntityState.Unchanged:
                        findMatch(
                            candidateEntry.CurrentValues,
                            (target) =>
                            {
                                currentReferenceEnd.Add(endMember, target);
                                originalReferenceEnd.Add(endMember, target);
                            });
                        break;
                    case EntityState.Added:
                        findMatch(
                            candidateEntry.CurrentValues,
                            (target) => currentReferenceEnd.Add(endMember, target));
                        break;
                    case EntityState.Deleted:
                        findMatch(
                            candidateEntry.OriginalValues,
                            (target) => originalReferenceEnd.Add(endMember, target));
                        break;
                    default:
                        break;
                }
            }