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
- ProjectionPlanCompiler.cs
- HtmlTableRowCollection.cs
- CodeSnippetCompileUnit.cs
- AliasGenerator.cs
- documentsequencetextcontainer.cs
- NameValuePermission.cs
- SecureStringHasher.cs
- PathNode.cs
- ConstraintStruct.cs
- SecurityElement.cs
- Utilities.cs
- BaseCodeDomTreeGenerator.cs
- RangeValuePattern.cs
- StringCollectionEditor.cs
- OdbcParameter.cs
- FaultDesigner.cs
- ConfigurationElement.cs
- PathSegment.cs
- SizeAnimationClockResource.cs
- MarkupCompilePass2.cs
- DispatcherProcessingDisabled.cs
- Encoder.cs
- PersonalizationStateInfoCollection.cs
- QilValidationVisitor.cs
- SequenceDesigner.cs
- Misc.cs
- ResXBuildProvider.cs
- XmlSchemaComplexContent.cs
- ObjectIDGenerator.cs
- MsmqInputMessage.cs
- Hash.cs
- DrawingGroup.cs
- ChangeBlockUndoRecord.cs
- PreviewPageInfo.cs
- MenuAdapter.cs
- ConnectionStringsExpressionBuilder.cs
- CompModHelpers.cs
- DataGridViewCellStyleConverter.cs
- ExceptionTranslationTable.cs
- HtmlContainerControl.cs
- PeerApplication.cs
- PageBuildProvider.cs
- SolidColorBrush.cs
- CommandHelper.cs
- DodSequenceMerge.cs
- SimpleMailWebEventProvider.cs
- TypeDescriptionProviderAttribute.cs
- RequestBringIntoViewEventArgs.cs
- CurrentTimeZone.cs
- EncryptedType.cs
- DesignSurfaceCollection.cs
- ZoomingMessageFilter.cs
- HttpHandlerActionCollection.cs
- ContextInformation.cs
- ToolStripTextBox.cs
- SqlMethodCallConverter.cs
- DataControlLinkButton.cs
- NetworkStream.cs
- ApplicationInfo.cs
- DataObjectEventArgs.cs
- UnmanagedMemoryStream.cs
- DesignTimeTemplateParser.cs
- PanelDesigner.cs
- _OverlappedAsyncResult.cs
- SafeEventLogWriteHandle.cs
- LoginUtil.cs
- IndexedEnumerable.cs
- HealthMonitoringSectionHelper.cs
- TypeValidationEventArgs.cs
- Wrapper.cs
- HtmlInputHidden.cs
- ProjectionCamera.cs
- StylusPoint.cs
- HandleExceptionArgs.cs
- AttachedPropertyBrowsableAttribute.cs
- Rect3DConverter.cs
- RangeValidator.cs
- InkPresenterAutomationPeer.cs
- ErrorFormatterPage.cs
- ConnectionString.cs
- LinkConverter.cs
- NullableConverter.cs
- StoreContentChangedEventArgs.cs
- Completion.cs
- UserControl.cs
- ScriptManager.cs
- NextPreviousPagerField.cs
- ManifestResourceInfo.cs
- TypeToken.cs
- BaseCAMarshaler.cs
- RelatedPropertyManager.cs
- SoapAttributeAttribute.cs
- Variable.cs
- PopOutPanel.cs
- ConfigDefinitionUpdates.cs
- HtmlCommandAdapter.cs
- SuppressMergeCheckAttribute.cs
- ScrollChrome.cs
- Buffer.cs
- SiteMapNode.cs