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
- KeyValueConfigurationElement.cs
- MobilePage.cs
- AuthenticodeSignatureInformation.cs
- TableRow.cs
- DocumentOrderComparer.cs
- AppSettingsSection.cs
- ReaderContextStackData.cs
- Part.cs
- EntityRecordInfo.cs
- QueryReaderSettings.cs
- DataTemplate.cs
- ThreadAttributes.cs
- TypeBuilderInstantiation.cs
- ErrorWebPart.cs
- TreeView.cs
- AsyncParams.cs
- NumberEdit.cs
- FormattedTextSymbols.cs
- AnnotationStore.cs
- NumericExpr.cs
- Command.cs
- _StreamFramer.cs
- base64Transforms.cs
- SingleAnimationBase.cs
- LoginCancelEventArgs.cs
- XmlSchemaCollection.cs
- Pkcs7Recipient.cs
- HttpResponseWrapper.cs
- Input.cs
- OleTxTransaction.cs
- NamespaceList.cs
- FormViewPagerRow.cs
- ImplicitInputBrush.cs
- BaseComponentEditor.cs
- X509ScopedServiceCertificateElementCollection.cs
- TrackingAnnotationCollection.cs
- DependsOnAttribute.cs
- FileDialog_Vista_Interop.cs
- IPPacketInformation.cs
- VScrollProperties.cs
- HMACMD5.cs
- BitmapEffectInputConnector.cs
- Matrix.cs
- TextEditorContextMenu.cs
- Baml6Assembly.cs
- ContainerAction.cs
- Helper.cs
- ResourceContainer.cs
- OleDbPropertySetGuid.cs
- StagingAreaInputItem.cs
- CompiledRegexRunner.cs
- ServerValidateEventArgs.cs
- WebHttpSecurityElement.cs
- InputMethodStateChangeEventArgs.cs
- Thickness.cs
- _WinHttpWebProxyDataBuilder.cs
- InputScopeNameConverter.cs
- ApplicationFileCodeDomTreeGenerator.cs
- AlignmentXValidation.cs
- Table.cs
- EventHandlerList.cs
- ConnectionStringsExpressionEditor.cs
- GZipDecoder.cs
- COM2PropertyPageUITypeConverter.cs
- HttpRequestCacheValidator.cs
- EntityObject.cs
- InternalPolicyElement.cs
- TrackBarRenderer.cs
- XmlDocumentFragment.cs
- MailMessage.cs
- PersistNameAttribute.cs
- HttpResponse.cs
- FamilyTypeface.cs
- GeneralTransform.cs
- CodeDomDecompiler.cs
- SQLStringStorage.cs
- EncoderParameter.cs
- ComPlusAuthorization.cs
- TargetPerspective.cs
- RubberbandSelector.cs
- ThicknessKeyFrameCollection.cs
- DefaultMemberAttribute.cs
- AnnotationService.cs
- FlowDocumentReader.cs
- ComboBox.cs
- ImageDesigner.cs
- SizeF.cs
- ConfigurationValidatorAttribute.cs
- NativeMethods.cs
- BrushConverter.cs
- UTF7Encoding.cs
- ResourceDescriptionAttribute.cs
- ConfigurationManagerInternalFactory.cs
- WinCategoryAttribute.cs
- IndexOutOfRangeException.cs
- FormsAuthenticationUserCollection.cs
- WinEventHandler.cs
- TemplatePartAttribute.cs
- DataListItemEventArgs.cs
- EntityTypeEmitter.cs