Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / ndp / fx / src / DataEntity / System / Data / Objects / DataClasses / EntityReference.cs / 1 / 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
- PropertyTabChangedEvent.cs
- TriggerBase.cs
- OpenTypeCommon.cs
- StreamWithDictionary.cs
- RawTextInputReport.cs
- RequestSecurityTokenResponse.cs
- ToolboxBitmapAttribute.cs
- CodeParameterDeclarationExpression.cs
- CodeBlockBuilder.cs
- XmlLanguage.cs
- AssemblyBuilderData.cs
- NameValueConfigurationCollection.cs
- RegularExpressionValidator.cs
- FreezableCollection.cs
- InternalUserCancelledException.cs
- EntityDataSourceDesignerHelper.cs
- HtmlInputImage.cs
- BlurBitmapEffect.cs
- FontWeights.cs
- HttpModulesSection.cs
- CompressionTransform.cs
- TouchesOverProperty.cs
- SchemaSetCompiler.cs
- HighlightVisual.cs
- AsyncMethodInvoker.cs
- PeerTransportListenAddressValidatorAttribute.cs
- RootBrowserWindowAutomationPeer.cs
- CreateUserWizard.cs
- DesignerVerbCollection.cs
- ProtectedUri.cs
- RsaSecurityKey.cs
- SqlBulkCopyColumnMappingCollection.cs
- GlyphElement.cs
- UpDownBase.cs
- UserMapPath.cs
- FaultReasonText.cs
- compensatingcollection.cs
- TextEffect.cs
- VirtualDirectoryMappingCollection.cs
- XmlSchemaAttributeGroupRef.cs
- Blend.cs
- LogicalChannel.cs
- ChildTable.cs
- FtpCachePolicyElement.cs
- ActivityExecutorSurrogate.cs
- RijndaelManaged.cs
- BitmapEffectDrawing.cs
- ModelToObjectValueConverter.cs
- MarshalByValueComponent.cs
- ColumnCollectionEditor.cs
- CheckBoxBaseAdapter.cs
- TouchPoint.cs
- CssClassPropertyAttribute.cs
- SimpleHandlerBuildProvider.cs
- XmlChoiceIdentifierAttribute.cs
- CheckableControlBaseAdapter.cs
- WebPartDisplayModeCancelEventArgs.cs
- ReflectionPermission.cs
- TemplateManager.cs
- ViewStateModeByIdAttribute.cs
- EmptyEnumerator.cs
- FieldNameLookup.cs
- ListItem.cs
- IndexerNameAttribute.cs
- TextShapeableCharacters.cs
- StorageModelBuildProvider.cs
- SystemGatewayIPAddressInformation.cs
- DataGridViewColumnDividerDoubleClickEventArgs.cs
- PasswordBoxAutomationPeer.cs
- XmlSerializationGeneratedCode.cs
- BitmapEffectInput.cs
- SimpleFieldTemplateUserControl.cs
- BufferedGenericXmlSecurityToken.cs
- DocumentSchemaValidator.cs
- WhileDesigner.cs
- Operators.cs
- CookieParameter.cs
- ScriptResourceAttribute.cs
- CapabilitiesUse.cs
- Closure.cs
- VisualTarget.cs
- RulePatternOps.cs
- DeploymentSection.cs
- WindowsPen.cs
- SchemaMerger.cs
- XamlSerializationHelper.cs
- GraphicsContainer.cs
- XmlComplianceUtil.cs
- ComponentRenameEvent.cs
- FontStretches.cs
- ScrollChrome.cs
- xmlsaver.cs
- ErrorWebPart.cs
- GridViewPageEventArgs.cs
- AddInIpcChannel.cs
- ListSourceHelper.cs
- MouseButtonEventArgs.cs
- IItemContainerGenerator.cs
- AsymmetricAlgorithm.cs
- ConfigXmlComment.cs