Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / ndp / fx / src / DataEntity / System / Data / Objects / DataClasses / EntityReference.cs / 2 / EntityReference.cs
//---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....] // @backupOwner [....] //--------------------------------------------------------------------- using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Data.Common; using System.Data.Common.CommandTrees; using System.Data.Metadata.Edm; using System.Diagnostics; using System.Runtime.Serialization; namespace System.Data.Objects.DataClasses { ////// Models a relationship end with multiplicity 1. /// [DataContract] [Serializable] public abstract class EntityReference : RelatedEnd { // ------ // Fields // ------ // The following fields are serialized. Adding or removing a serialized field is considered // a breaking change. This includes changing the field type or field name of existing // serialized fields. If you need to make this kind of change, it may be possible, but it // will require some custom serialization/deserialization code. // The following field is valid only for detached EntityReferences, see EntityKey property for more details. private EntityKey _detachedEntityKey = null; // ------------ // Constructors // ------------ ////// The default constructor is required for some serialization scenarios. It should not be used to /// create new EntityReferences. Use the GetRelatedReference or GetRelatedEnd methods on the RelationshipManager /// class instead. /// protected EntityReference() { } internal EntityReference(IEntityWithRelationships owner, RelationshipNavigation navigation, IRelationshipFixer relationshipFixer) : base(owner, navigation, relationshipFixer) { } ////// Returns the EntityKey of the target entity associated with this EntityReference. /// /// Is non-null in the following scenarios: /// (a) Entities are tracked by a context and an Unchanged or Added client-side relationships exists for this EntityReference's owner with the /// same RelationshipName and source role. This relationship could have been created explicitly by the user (e.g. by setting /// the EntityReference.Value, setting this property directly, or by calling EntityCollection.Add) or automatically through span queries. /// (b) If the EntityKey was non-null before detaching an entity from the context, it will still be non-null after detaching, until any operation /// occurs that would set it to null, as described below. /// (c) Entities are detached and the EntityKey is explicitly set to non-null by the user. /// (d) Entity graph was created using a NoTracking query with full span /// /// Is null in the following scenarios: /// (a) Entities are tracked by a context but there is no Unchanged or Added client-side relationship for this EntityReference's owner with the /// same RelationshipName and source role. /// (b) Entities are tracked by a context and a relationship exists, but the target entity has a temporary key (i.e. it is Added) or the key /// is one of the special keys /// (c) Entities are detached and the relationship was explicitly created by the user. /// [DataMember] public EntityKey EntityKey { // This is the only scenario where it is valid to have a null Owner, so don't check it get { if (this.ObjectContext != null && !UsingNoTracking) { Debug.Assert(this.Owner != null, "Unexpected null Owner on EntityReference attached to a context"); EntityKey attachedKey = null; // If this EntityReference contains an entity, look up the key on that object if (CachedValue != null) { // Since this EntityReference is attached to a context, the contained entity must // also be attached and will therefore always have a key attachedKey = this.ObjectContext.ObjectStateManager.GetEntityKey(CachedValue); if (!IsValidEntityKeyType(attachedKey)) { // don't return temporary or special keys from this property attachedKey = null; } } else { // There could still be an Added or Unchanged relationship with a stub entry EntityKey ownerKey = ObjectContext.FindEntityKey(this.Owner, this.ObjectContext); foreach (ObjectStateEntry relationshipEntry in this.ObjectContext.ObjectStateManager.FindRelationshipsByKey(ownerKey)) { // We only care about the relationships that match the AssociationSet and source role for the owner of this EntityReference if (relationshipEntry.State != EntityState.Deleted && relationshipEntry.IsSameAssociationSetAndRole((AssociationSet)RelationshipSet, ownerKey, (AssociationEndMember)this.FromEndProperty)) { Debug.Assert(attachedKey == null, "Found more than one non-Deleted relationship for the same AssociationSet and source role"); attachedKey = relationshipEntry.Wrapper.GetOtherEntityKey(ownerKey); // key should never be temporary or special since it came from a key entry } } } Debug.Assert(attachedKey == null || IsValidEntityKeyType(attachedKey), "Unexpected temporary or special key"); return attachedKey; } else { return _detachedEntityKey; } } set { if (value != null && value == EntityKey) { // "no-op" -- this is not really no-op in the attached case, because at a minimum we have to do a key lookup, // worst case we have to review all relationships for the owner entity // However, if we don't do this, we can get into a scenario where we are setting the key to the same thing it's already set to // and this could have side effects, especially with RI constraints and cascade delete. We don't want to delete something // and then add it back, if that deleting could have additional unexpected effects. Don't bother doing this check if value is // null, because EntityKey could be null even if there are Added/Unchanged relationships, if the target entity has a temporary key. // In that case, we still need to delete that existing relationship, so it's not a no-op return; } if (this.ObjectContext != null && !UsingNoTracking) { Debug.Assert(this.Owner != null, "Unexpected null Owner on EntityReference attached to a context"); // null is a valid value for the EntityKey, but temporary and special keys are not // devnote: Can't check this on detached references because this property could be set to a temp key during deserialization, // if the key hasn't finished deserializing yet. if (value != null && !IsValidEntityKeyType(value)) { throw EntityUtil.CannotSetSpecialKeys(); } if (value == null) { // delegate to Value property for all validation and firing of events this.ReferenceValue = null; } else { // Verify that the key has the right EntitySet for this RelationshipSet EntitySet targetEntitySet = value.GetEntitySet(ObjectContext.MetadataWorkspace); CheckRelationEntitySet(targetEntitySet); value.ValidateEntityKey(targetEntitySet, true /*isArgumentException */, "value"); ObjectStateManager manager = this.ObjectContext.ObjectStateManager; // If we already have an entry with this key, we just need to create a relationship with it bool addNewRelationship = false; // If we don't already have any matching entries for this key, we'll have to create a new entry bool addKeyEntry = false; ObjectStateEntry targetEntry = manager.FindObjectStateEntry(value); if (targetEntry != null) { // If it's not a key entry, just use the entity to set this reference's Value if (!targetEntry.IsKeyEntry) { // Delegate to the Value property to clear any existing relationship // and to add the new one. This will fire the appropriate events and // ensure that the related ends are connected. // It has to be a TEntity since we already verified that the EntitySet is correct above this.ReferenceValue = targetEntry.Entity; } else { // if the existing entry is a key entry, we just need to // add a new relationship between the source entity and that key addNewRelationship = true; } } else { // no entry exists, so we'll need to add a key along with the relationship addKeyEntry = true; addNewRelationship = true; } if (addNewRelationship) { EntityKey ownerKey = ValidateOwnerWithRIConstraints(); // Verify that the owner is in a valid state for adding a relationship ValidateStateForAdd(this.Owner); if (addKeyEntry) { manager.AddKeyEntry(value, targetEntitySet); } // First, clear any existing relationships ClearCollectionOrRef(null, null, /*doCascadeDelete*/ false); // Then add the new one RelationshipWrapper wrapper = new RelationshipWrapper((AssociationSet)RelationshipSet, RelationshipNavigation.From, ownerKey, RelationshipNavigation.To, value); manager.AddNewRelation(wrapper, EntityState.Added); } } } else { // Just set the field for detached object -- during Attach/Add we will make sure this value // is not in conflict if the EntityReference contains a real entity. We cannot always determine the // EntityKey for any real entity in the detached state, so we don't bother to do it here. _detachedEntityKey = value; } } } internal EntityKey AttachedEntityKey { get { Debug.Assert(this.ObjectContext != null && !UsingNoTracking, "Should only need to access AttachedEntityKey property on attached EntityReferences"); return this.EntityKey; } } internal EntityKey DetachedEntityKey { get { return _detachedEntityKey; } set { _detachedEntityKey = value; } } internal abstract object CachedValue { get; } internal abstract object ReferenceValue { get; set; } internal EntityKey ValidateOwnerWithRIConstraints() { EntityKey ownerKey = ObjectStateManager.FindKeyOnEntityWithRelationships(Owner); /* Check if Referential Constraints are violated */ if ((object)ownerKey != null && !ownerKey.IsTemporary && IsDependentEndOfReferentialConstraint()) { throw EntityUtil.CannotChangeReferentialConstraintProperty(); } return ownerKey; } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....] // @backupOwner [....] //--------------------------------------------------------------------- using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Data.Common; using System.Data.Common.CommandTrees; using System.Data.Metadata.Edm; using System.Diagnostics; using System.Runtime.Serialization; namespace System.Data.Objects.DataClasses { ////// Models a relationship end with multiplicity 1. /// [DataContract] [Serializable] public abstract class EntityReference : RelatedEnd { // ------ // Fields // ------ // The following fields are serialized. Adding or removing a serialized field is considered // a breaking change. This includes changing the field type or field name of existing // serialized fields. If you need to make this kind of change, it may be possible, but it // will require some custom serialization/deserialization code. // The following field is valid only for detached EntityReferences, see EntityKey property for more details. private EntityKey _detachedEntityKey = null; // ------------ // Constructors // ------------ ////// The default constructor is required for some serialization scenarios. It should not be used to /// create new EntityReferences. Use the GetRelatedReference or GetRelatedEnd methods on the RelationshipManager /// class instead. /// protected EntityReference() { } internal EntityReference(IEntityWithRelationships owner, RelationshipNavigation navigation, IRelationshipFixer relationshipFixer) : base(owner, navigation, relationshipFixer) { } ////// Returns the EntityKey of the target entity associated with this EntityReference. /// /// Is non-null in the following scenarios: /// (a) Entities are tracked by a context and an Unchanged or Added client-side relationships exists for this EntityReference's owner with the /// same RelationshipName and source role. This relationship could have been created explicitly by the user (e.g. by setting /// the EntityReference.Value, setting this property directly, or by calling EntityCollection.Add) or automatically through span queries. /// (b) If the EntityKey was non-null before detaching an entity from the context, it will still be non-null after detaching, until any operation /// occurs that would set it to null, as described below. /// (c) Entities are detached and the EntityKey is explicitly set to non-null by the user. /// (d) Entity graph was created using a NoTracking query with full span /// /// Is null in the following scenarios: /// (a) Entities are tracked by a context but there is no Unchanged or Added client-side relationship for this EntityReference's owner with the /// same RelationshipName and source role. /// (b) Entities are tracked by a context and a relationship exists, but the target entity has a temporary key (i.e. it is Added) or the key /// is one of the special keys /// (c) Entities are detached and the relationship was explicitly created by the user. /// [DataMember] public EntityKey EntityKey { // This is the only scenario where it is valid to have a null Owner, so don't check it get { if (this.ObjectContext != null && !UsingNoTracking) { Debug.Assert(this.Owner != null, "Unexpected null Owner on EntityReference attached to a context"); EntityKey attachedKey = null; // If this EntityReference contains an entity, look up the key on that object if (CachedValue != null) { // Since this EntityReference is attached to a context, the contained entity must // also be attached and will therefore always have a key attachedKey = this.ObjectContext.ObjectStateManager.GetEntityKey(CachedValue); if (!IsValidEntityKeyType(attachedKey)) { // don't return temporary or special keys from this property attachedKey = null; } } else { // There could still be an Added or Unchanged relationship with a stub entry EntityKey ownerKey = ObjectContext.FindEntityKey(this.Owner, this.ObjectContext); foreach (ObjectStateEntry relationshipEntry in this.ObjectContext.ObjectStateManager.FindRelationshipsByKey(ownerKey)) { // We only care about the relationships that match the AssociationSet and source role for the owner of this EntityReference if (relationshipEntry.State != EntityState.Deleted && relationshipEntry.IsSameAssociationSetAndRole((AssociationSet)RelationshipSet, ownerKey, (AssociationEndMember)this.FromEndProperty)) { Debug.Assert(attachedKey == null, "Found more than one non-Deleted relationship for the same AssociationSet and source role"); attachedKey = relationshipEntry.Wrapper.GetOtherEntityKey(ownerKey); // key should never be temporary or special since it came from a key entry } } } Debug.Assert(attachedKey == null || IsValidEntityKeyType(attachedKey), "Unexpected temporary or special key"); return attachedKey; } else { return _detachedEntityKey; } } set { if (value != null && value == EntityKey) { // "no-op" -- this is not really no-op in the attached case, because at a minimum we have to do a key lookup, // worst case we have to review all relationships for the owner entity // However, if we don't do this, we can get into a scenario where we are setting the key to the same thing it's already set to // and this could have side effects, especially with RI constraints and cascade delete. We don't want to delete something // and then add it back, if that deleting could have additional unexpected effects. Don't bother doing this check if value is // null, because EntityKey could be null even if there are Added/Unchanged relationships, if the target entity has a temporary key. // In that case, we still need to delete that existing relationship, so it's not a no-op return; } if (this.ObjectContext != null && !UsingNoTracking) { Debug.Assert(this.Owner != null, "Unexpected null Owner on EntityReference attached to a context"); // null is a valid value for the EntityKey, but temporary and special keys are not // devnote: Can't check this on detached references because this property could be set to a temp key during deserialization, // if the key hasn't finished deserializing yet. if (value != null && !IsValidEntityKeyType(value)) { throw EntityUtil.CannotSetSpecialKeys(); } if (value == null) { // delegate to Value property for all validation and firing of events this.ReferenceValue = null; } else { // Verify that the key has the right EntitySet for this RelationshipSet EntitySet targetEntitySet = value.GetEntitySet(ObjectContext.MetadataWorkspace); CheckRelationEntitySet(targetEntitySet); value.ValidateEntityKey(targetEntitySet, true /*isArgumentException */, "value"); ObjectStateManager manager = this.ObjectContext.ObjectStateManager; // If we already have an entry with this key, we just need to create a relationship with it bool addNewRelationship = false; // If we don't already have any matching entries for this key, we'll have to create a new entry bool addKeyEntry = false; ObjectStateEntry targetEntry = manager.FindObjectStateEntry(value); if (targetEntry != null) { // If it's not a key entry, just use the entity to set this reference's Value if (!targetEntry.IsKeyEntry) { // Delegate to the Value property to clear any existing relationship // and to add the new one. This will fire the appropriate events and // ensure that the related ends are connected. // It has to be a TEntity since we already verified that the EntitySet is correct above this.ReferenceValue = targetEntry.Entity; } else { // if the existing entry is a key entry, we just need to // add a new relationship between the source entity and that key addNewRelationship = true; } } else { // no entry exists, so we'll need to add a key along with the relationship addKeyEntry = true; addNewRelationship = true; } if (addNewRelationship) { EntityKey ownerKey = ValidateOwnerWithRIConstraints(); // Verify that the owner is in a valid state for adding a relationship ValidateStateForAdd(this.Owner); if (addKeyEntry) { manager.AddKeyEntry(value, targetEntitySet); } // First, clear any existing relationships ClearCollectionOrRef(null, null, /*doCascadeDelete*/ false); // Then add the new one RelationshipWrapper wrapper = new RelationshipWrapper((AssociationSet)RelationshipSet, RelationshipNavigation.From, ownerKey, RelationshipNavigation.To, value); manager.AddNewRelation(wrapper, EntityState.Added); } } } else { // Just set the field for detached object -- during Attach/Add we will make sure this value // is not in conflict if the EntityReference contains a real entity. We cannot always determine the // EntityKey for any real entity in the detached state, so we don't bother to do it here. _detachedEntityKey = value; } } } internal EntityKey AttachedEntityKey { get { Debug.Assert(this.ObjectContext != null && !UsingNoTracking, "Should only need to access AttachedEntityKey property on attached EntityReferences"); return this.EntityKey; } } internal EntityKey DetachedEntityKey { get { return _detachedEntityKey; } set { _detachedEntityKey = value; } } internal abstract object CachedValue { get; } internal abstract object ReferenceValue { get; set; } internal EntityKey ValidateOwnerWithRIConstraints() { EntityKey ownerKey = ObjectStateManager.FindKeyOnEntityWithRelationships(Owner); /* Check if Referential Constraints are violated */ if ((object)ownerKey != null && !ownerKey.IsTemporary && IsDependentEndOfReferentialConstraint()) { throw EntityUtil.CannotChangeReferentialConstraintProperty(); } return ownerKey; } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- StandardToolWindows.cs
- PipeException.cs
- SerializationFieldInfo.cs
- ProviderConnectionPoint.cs
- NativeMethods.cs
- NonVisualControlAttribute.cs
- DataServiceHost.cs
- ExclusiveTcpTransportManager.cs
- DecoderExceptionFallback.cs
- InvalidOperationException.cs
- Int64Converter.cs
- Publisher.cs
- HttpApplicationFactory.cs
- EntitySqlQueryBuilder.cs
- ServiceModelActivity.cs
- CompoundFileIOPermission.cs
- ScrollChangedEventArgs.cs
- TransformerConfigurationWizardBase.cs
- XamlTypeMapper.cs
- ActivitiesCollection.cs
- Point3D.cs
- TextInfo.cs
- OutgoingWebRequestContext.cs
- XmlILStorageConverter.cs
- SchemaImporterExtensionsSection.cs
- EntityParameter.cs
- ProcessThreadDesigner.cs
- DnsPermission.cs
- CacheOutputQuery.cs
- SupportingTokenSpecification.cs
- ConnectionProviderAttribute.cs
- TrackBarRenderer.cs
- HyperLink.cs
- AutomationAttributeInfo.cs
- DynamicDocumentPaginator.cs
- ToolTipAutomationPeer.cs
- AuthenticationException.cs
- SqlMethodAttribute.cs
- DataSourceSelectArguments.cs
- SingleConverter.cs
- TdsParserHelperClasses.cs
- InstanceCompleteException.cs
- EntityKey.cs
- FieldMetadata.cs
- TabRenderer.cs
- RuntimeConfigLKG.cs
- AndCondition.cs
- HuffmanTree.cs
- MatrixAnimationBase.cs
- CqlParser.cs
- InvalidFilterCriteriaException.cs
- WebPartConnectionsDisconnectVerb.cs
- RecordManager.cs
- _StreamFramer.cs
- COAUTHINFO.cs
- BufferedReadStream.cs
- HttpTransportBindingElement.cs
- TdsRecordBufferSetter.cs
- Roles.cs
- WebPartEditorCancelVerb.cs
- ActivityMetadata.cs
- DataGridViewColumnCollection.cs
- MappingModelBuildProvider.cs
- XsltOutput.cs
- Light.cs
- WebBrowserNavigatedEventHandler.cs
- PeerDuplexChannel.cs
- ParallelLoopState.cs
- Hex.cs
- ChangeDirector.cs
- EncoderParameter.cs
- ShaperBuffers.cs
- DragCompletedEventArgs.cs
- FileDialogCustomPlace.cs
- CheckBoxList.cs
- UpdateProgress.cs
- DocumentGrid.cs
- Matrix3DStack.cs
- DeclaredTypeElement.cs
- ExpressionBuilder.cs
- DrawingCollection.cs
- PersistChildrenAttribute.cs
- XmlLoader.cs
- RuleEngine.cs
- SplitterPanelDesigner.cs
- WaitForChangedResult.cs
- SqlTypeSystemProvider.cs
- SystemException.cs
- ContextStaticAttribute.cs
- CustomErrorsSection.cs
- embossbitmapeffect.cs
- CellConstantDomain.cs
- ReflectPropertyDescriptor.cs
- BrowserTree.cs
- ViewBase.cs
- KoreanCalendar.cs
- ObsoleteAttribute.cs
- SessionSwitchEventArgs.cs
- WithParamAction.cs
- ShapeTypeface.cs