EntityDescriptor.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataWeb / Client / System / Data / Services / Client / EntityDescriptor.cs / 1305376 / EntityDescriptor.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//  
// represents the object and state
//  
//--------------------------------------------------------------------- 

namespace System.Data.Services.Client 
{
    using System.Diagnostics;
    using System.Globalization;
 
    /// 
    /// represents the cached entity 
    ///  
    [DebuggerDisplay("State = {state}, Uri = {editLink}, Element = {entity.GetType().ToString()}")]
    public sealed class EntityDescriptor : Descriptor 
    {
        #region Fields

        /// uri to identitfy the entity 
        /// <atom:id>identity</id>
        private String identity; 
 
        /// entity
        private object entity; 

        /// entity tag
        private string etag;
 
        /// ETag for the media resource if this is a media link entry.
        private string streamETag; 
 
        /// The parent resource that this resource is linked to.
        private EntityDescriptor parentDescriptor; 

        /// Parent resource property to which this node is linked
        private string parentProperty;
 
        /// String storing the server type related to this entity
        private string serverTypeName; 
 
        /// uri to query the entity
        /// <atom:link rel="self" href="queryLink" /> 
        private Uri selfLink;

        /// uri to edit the entity. In case of deep add, this can also refer to the navigation property name.
        /// <atom:link rel="edit" href="editLink" /> 
        private Uri editLink;
 
        /// In case of Media Link Entry, this is the link to the Media Resource (content). 
        /// Otherwise this is null.
        /// <atom:content src="contentLink" /> 
        private Uri readStreamLink;

        /// In case of Media Link Entry, this is the edit-media link value.
        /// Otherwise this is null. 
        /// <atom:link rel="edit-media" href="editMediaLink" />
        private Uri editMediaLink; 
 
        /// The save stream associated with this MLE.
        /// When set the entity is treated as MLE and will participate in SaveChanges 
        /// (even if its state is Unmodified). If the state of the entity is Added first
        /// the MR will be POSTed using this stream as the content then the entity will be PUT/MERGE as MLE.
        /// If the state of the entity is Unmodified only the MR will be PUT using this stream as the content.
        /// If the state of the entity is Changed first the MR will be PUT using this stream as the content 
        /// and then the entity will be PUT/MERGE as MLE.
        /// If the state of the entity is Deleted this stream is not going to be used. 
        /// 
        /// SaveChanges will call CloseSaveStream on this object after it returns regardless of it succeeding or not.
        /// SaveChanges will call the method even if it didn't get to process the entity (failed sooner). 
        /// The CloseSaveStream method will close the stream if it's owned by the object and will set this field to null.
        private DataServiceContext.DataServiceSaveStream saveStream;

        /// Set to true if the entity represented by this box is an MLE entity. 
        /// Since in some cases we don't know upfront if the entity is MLE or not, we use this boolean to remember the fact
        /// once we learn it. For example for POCO entities the entity becomes MLE only once a SetSaveStream is called on it. 
        /// Also once the entity has become MLE it can't change that while we're tracking it (since it will be MLE on the server as well). 
        /// That's why we only set thhis to true and never back to false.
        private bool mediaLinkEntry; 

        /// 
        /// Describes whether the SaveStream is for Insert or Update.
        /// The value NoStream is for both non-MLEs and MLEs with unmodified stream. 
        /// 
        private StreamStates streamState; 
 
        /// 
        /// The entity set name to be used to insert the entity. 
        /// 
        private string entitySetName;

        #endregion 

        ///  
        /// Constructor 
        /// 
        /// resource Uri 
        /// query link of entity
        /// edit link of entity
        /// entity
        /// parent entity 
        /// Parent entity property to which this entity is linked
        /// name of the entity set to which the entity belongs. 
        /// etag 
        /// entity state
        internal EntityDescriptor(String identity, Uri selfLink, Uri editLink, object entity, EntityDescriptor parentEntity, string parentProperty, string entitySetName, string etag, EntityStates state) 
            : base(state)
        {
            Debug.Assert(entity != null, "entity is null");
            Debug.Assert((parentEntity == null && parentProperty == null) || (parentEntity != null && parentProperty != null), "When parentEntity is specified, must also specify parentProperyName"); 

#if DEBUG 
            if (state == EntityStates.Added) 
            {
                Debug.Assert(identity == null && selfLink == null && editLink == null && etag == null, "For objects in added state, identity, self-link, edit-link and etag must be null"); 
                Debug.Assert((!String.IsNullOrEmpty(entitySetName) && parentEntity == null && String.IsNullOrEmpty(parentProperty)) ||
                             (String.IsNullOrEmpty(entitySetName) && parentEntity != null && !String.IsNullOrEmpty(parentProperty)),
                             "For entities in added state, entity set name or the insert path must be specified");
            } 
            else
            { 
                // For some read-only service, editlink can be null. They can only specify self-links. 
                Debug.Assert(identity != null, "For objects in non-added state, identity must never be null");
                Debug.Assert(String.IsNullOrEmpty(entitySetName) && String.IsNullOrEmpty(parentProperty) && parentEntity == null, "For non-added entities, the entity set name and the insert path must be null"); 
            }
#endif

            // Identity can be null if object is just added (AddObject) 
            this.identity = identity;
            this.selfLink = selfLink; 
            this.editLink = editLink; 

            this.parentDescriptor = parentEntity; 
            this.parentProperty = parentProperty;
            this.entity = entity;
            this.etag = etag;
            this.entitySetName = entitySetName; 
        }
 
        #region Properties 

        /// entity uri identity 
        public String Identity
        {
            get
            { 
                return this.identity;
            } 
 
            internal set
            { 
                Util.CheckArgumentNotEmpty(value, "Identity");
                this.identity = value;
                this.parentDescriptor = null;
                this.parentProperty = null; 
                this.entitySetName = null;
            } 
        } 

        /// uri to query entity 
        public Uri SelfLink
        {
            get { return this.selfLink; }
            internal set { this.selfLink = value; } 
        }
 
        /// uri to edit entity 
        public Uri EditLink
        { 
            get { return this.editLink; }
            internal set { this.editLink = value; }
        }
 
        /// 
        /// If the entity for the box is an MLE this property stores the content source URI of the MLE. 
        /// That is, it stores the read URI for the associated MR. 
        /// Setting it to non-null marks the entity as MLE.
        ///  
        public Uri ReadStreamUri
        {
            get
            { 
                return this.readStreamLink;
            } 
 
            internal set
            { 
                this.readStreamLink = value;
                if (value != null)
                {
                    this.mediaLinkEntry = true; 
                }
            } 
        } 

        ///  
        /// If the entity for the box is an MLE this property stores the edit-media link URI.
        /// That is, it stores the URI to send PUTs for the associated MR.
        /// Setting it to non-null marks the entity as MLE.
        ///  
        public Uri EditStreamUri
        { 
            get 
            {
                return this.editMediaLink; 
            }

            internal set
            { 
                this.editMediaLink = value;
                if (value != null) 
                { 
                    this.mediaLinkEntry = true;
                } 
            }
        }

        /// entity 
        public object Entity
        { 
            get { return this.entity; } 
        }
 
        /// etag
        public string ETag
        {
            get { return this.etag; } 
            internal set { this.etag = value; }
        } 
 
        /// ETag for the media resource if this is a media link entry.
        public string StreamETag 
        {
            get
            {
                return this.streamETag; 
            }
 
            internal set 
            {
                Debug.Assert(this.mediaLinkEntry == true, "this.mediaLinkEntry == true"); 
                this.streamETag = value;
            }
        }
 
        /// Parent entity descriptor.
        /// This is only set for entities added through AddRelateObject call 
        public EntityDescriptor ParentForInsert 
        {
            get { return this.parentDescriptor; } 
        }

        /// Parent entity property to which this entity is linked
        public string ParentPropertyForInsert 
        {
            get { return this.parentProperty; } 
        } 

        /// Server type string 
        public String ServerTypeName
        {
            get { return this.serverTypeName; }
            internal set { this.serverTypeName = value; } 
        }
 
        #endregion 

        #region Internal Properties 
        // These properties are used internally for state tracking

        /// Parent entity
        internal object ParentEntity 
        {
            get { return this.parentDescriptor != null ? this.parentDescriptor.entity : null; } 
        } 

        /// this is a entity 
        internal override bool IsResource
        {
            get { return true; }
        } 

        ///  
        /// Returns true if the resource was inserted via its parent. E.g. POST customer(0)/Orders 
        /// 
        internal bool IsDeepInsert 
        {
            get { return this.parentDescriptor != null; }
        }
 
        /// 
        /// The stream which contains the new content for the MR associated with this MLE. 
        /// This stream is used during SaveChanges to POST/PUT the MR. 
        /// Setting it to non-null marks the entity as MLE.
        ///  
        internal DataServiceContext.DataServiceSaveStream SaveStream
        {
            get
            { 
                return this.saveStream;
            } 
 
            set
            { 
                this.saveStream = value;
                if (value != null)
                {
                    this.mediaLinkEntry = true; 
                }
            } 
        } 

        ///  
        /// Describes whether the SaveStream is for Insert or Update.
        /// The value NoStream is for both non-MLEs and MLEs with unmodified stream.
        /// 
        internal StreamStates StreamState 
        {
            get 
            { 
                return this.streamState;
            } 

            set
            {
                this.streamState = value; 
                Debug.Assert(this.streamState == StreamStates.NoStream || this.mediaLinkEntry, "this.streamState == StreamStates.NoStream || this.mediaLinkEntry");
                Debug.Assert( 
                    (this.saveStream == null && this.streamState == StreamStates.NoStream) || (this.saveStream != null && this.streamState != StreamStates.NoStream), 
                    "(this.saveStream == null && this.streamState == StreamStates.NoStream) || (this.saveStream != null && this.streamState != StreamStates.NoStream)");
            } 
        }

        /// 
        /// Returns true if we know that the entity is MLE. Note that this does not include the information 
        /// from the entity type. So if the entity was attributed with HasStream for example
        /// this boolean might not be aware of it. 
        ///  
        internal bool IsMediaLinkEntry
        { 
            get { return this.mediaLinkEntry; }
        }

        ///  
        /// Returns true if the entry has been modified (and thus should participate in SaveChanges).
        ///  
        internal override bool IsModified 
        {
            get 
            {
                if (base.IsModified)
                {
                    return true; 
                }
                else 
                { 
                    // If the entity is not modified but it does have a save stream associated with it
                    // it means that the MR for the MLE should be updated and thus we need to consider 
                    // the entity as modified (so that it shows up during SaveChanges)
                    return this.saveStream != null;
                }
            } 
        }
 
        #endregion 

        #region Internal Methods 

        /// uri to edit the entity
        /// baseUriWithSlash
        /// whether to return the query link or edit link 
        /// absolute uri which can be used to edit the entity
        internal Uri GetResourceUri(Uri baseUriWithSlash, bool queryLink) 
        { 
            // If the entity was inserted using the AddRelatedObject API
            if (this.parentDescriptor != null) 
            {
                // This is the batch scenario, where the entity might not have been saved yet, and there is another operation
                // (for e.g. PUT $1/links/BestFriend or something). Hence we need to generate a Uri with the changeorder number.
                if (this.parentDescriptor.Identity == null) 
                {
                    return Util.CreateUri( 
                        Util.CreateUri(baseUriWithSlash, new Uri("$" + this.parentDescriptor.ChangeOrder.ToString(CultureInfo.InvariantCulture), UriKind.Relative)), 
                        Util.CreateUri(this.parentProperty, UriKind.Relative));
                } 
                else
                {
                    return Util.CreateUri(Util.CreateUri(baseUriWithSlash, this.parentDescriptor.GetLink(queryLink)), this.GetLink(queryLink));
                } 
            }
            else 
            { 
                return Util.CreateUri(baseUriWithSlash, this.GetLink(queryLink));
            } 
        }

        /// is the entity the same as the source or target entity
        /// related end 
        /// true if same as source or target entity
        internal bool IsRelatedEntity(LinkDescriptor related) 
        { 
            return ((this.entity == related.Source) || (this.entity == related.Target));
        } 

        /// 
        /// Return the related end for this resource. One should call this method, only if the resource is inserted via deep resource.
        ///  
        /// returns the related end via which the resource was inserted.
        internal LinkDescriptor GetRelatedEnd() 
        { 
            Debug.Assert(this.IsDeepInsert, "For related end, this must be a deep insert");
            Debug.Assert(this.Identity == null, "If the identity is set, it means that the edit link no longer has the property name"); 

            return new LinkDescriptor(this.parentDescriptor.entity, this.parentProperty, this.entity);
        }
 
        /// 
        /// Closes the save stream if there's any and sets it to null 
        ///  
        internal void CloseSaveStream()
        { 
            if (this.saveStream != null)
            {
                DataServiceContext.DataServiceSaveStream stream = this.saveStream;
                this.saveStream = null; 
                stream.Close();
            } 
        } 

        ///  
        /// Returns the absolute URI for the media resource associated with this entity
        /// 
        /// The base uri of the service.
        /// Absolute URI of the media resource for this entity, or null if the entity is not an MLE. 
        internal Uri GetMediaResourceUri(Uri serviceBaseUri)
        { 
            return this.ReadStreamUri == null ? null : Util.CreateUri(serviceBaseUri, this.ReadStreamUri); 
        }
 
        /// 
        /// Returns the absolute URI for editing the media resource associated with this entity
        /// 
        /// The base uri of the service. 
        /// Absolute URI for editing the media resource for this entity, or null if the entity is not an MLE.
        internal Uri GetEditMediaResourceUri(Uri serviceBaseUri) 
        { 
            return this.EditStreamUri == null ? null : Util.CreateUri(serviceBaseUri, this.EditStreamUri);
        } 

        /// 
        /// In V1, we used to not support self links. Hence we used to use edit links as self links.
        /// IN V2, we are adding support for self links. But if there are not specified, we need to 
        /// fall back on the edit link.
        ///  
        /// whether to get query link or the edit link. 
        /// the query or the edit link, as specified in the  parameter.
        private Uri GetLink(bool queryLink) 
        {
            // If asked for a self link and self-link is present, return self link
            if (queryLink && this.SelfLink != null)
            { 
                return this.SelfLink;
            } 
 
            // otherwise return edit link if present.
            if (this.EditLink != null) 
            {
                return this.EditLink;
            }
 
            // If both self and edit links are not specified, the entity must be in added state, and we need
            // to compute the relative link from the entity set name or the parent property. 
            Debug.Assert(this.State == EntityStates.Added, "the entity must be in added state"); 
            if (!String.IsNullOrEmpty(this.entitySetName))
            { 
                return Util.CreateUri(this.entitySetName, UriKind.Relative);
            }
            else
            { 
                return Util.CreateUri(this.parentProperty, UriKind.Relative);
            } 
        } 

        #endregion 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK