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; }
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; } }
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, 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); } }
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; }
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()); }
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()); }
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; }
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(); }
/// <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(); }
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)); } } }
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); }
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()); } }
// 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)); }
/// <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)); }
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; } }
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; } }
/// <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); }
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; } }
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; } }