LazyLoadBehavior.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntity / System / Data / Objects / Internal / LazyLoadBehavior.cs / 1305376 / LazyLoadBehavior.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner       [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 

using System; 
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions; 
using System.Reflection;
using System.Reflection.Emit; 
using System.Security; 
using System.Security.Permissions;
using System.Data.Metadata.Edm; 
using System.Data.Objects.DataClasses;
using System.Collections;

namespace System.Data.Objects.Internal 
{
    ///  
    /// Defines and injects behavior into proxy class Type definitions 
    /// to allow navigation properties to lazily load their references or collection elements.
    ///  
    internal sealed class LazyLoadBehavior
    {
        /// 
        /// Return an expression tree that represents the actions required to load the related end 
        /// associated with the intercepted proxy member.
        ///  
        ///  
        /// EdmMember that specifies the member to be intercepted.
        ///  
        /// 
        /// PropertyInfo that specifies the CLR property to be intercepted.
        /// 
        ///  
        /// ParameterExpression that represents the proxy object.
        ///  
        ///  
        /// ParameterExpression that represents the proxied property value.
        ///  
        /// The Func that retrieves the wrapper from a proxy
        /// 
        /// Expression tree that encapsulates lazy loading behavior for the supplied member,
        /// or null if the expression tree could not be constructed. 
        /// 
        internal static Func GetInterceptorDelegate(EdmMember member, Func getEntityWrapperDelegate) 
            where TProxy : class 
            where TItem : class
        { 
            Func interceptorDelegate = (proxy, item) => true;

            Debug.Assert(member.BuiltInTypeKind == BuiltInTypeKind.NavigationProperty, "member should represent a navigation property");
            if (member.BuiltInTypeKind == BuiltInTypeKind.NavigationProperty) 
            {
                NavigationProperty navProperty = (NavigationProperty)member; 
                RelationshipMultiplicity multiplicity = navProperty.ToEndMember.RelationshipMultiplicity; 

                // Given the proxy and item parameters, construct one of the following expressions: 
                //
                // For collections:
                //  LazyLoadBehavior.LoadCollection(collection, "relationshipName", "targetRoleName", proxy._entityWrapperField)
                // 
                // For entity references:
                //  LazyLoadBehavior.LoadReference(item, "relationshipName", "targetRoleName", proxy._entityWrapperField) 
                // 
                // Both of these expressions return an object of the same type as the first parameter to LoadXYZ method.
                // In many cases, this will be the first parameter. 

                if (multiplicity == RelationshipMultiplicity.Many)
                {
                    interceptorDelegate = (proxy, item) => LoadProperty(item, 
                                                                               navProperty.RelationshipType.Identity,
                                                                               navProperty.ToEndMember.Identity, 
                                                                               false, 
                                                                               getEntityWrapperDelegate(proxy));
                } 
                else
                {
                    interceptorDelegate = (proxy, item) => LoadProperty(item,
                                                                               navProperty.RelationshipType.Identity, 
                                                                               navProperty.ToEndMember.Identity,
                                                                               true, 
                                                                               getEntityWrapperDelegate(proxy)); 
                }
            } 

            return interceptorDelegate;
        }
 
        /// 
        /// Determine if the specified member is compatible with lazy loading. 
        ///  
        /// 
        /// OSpace EntityType representing a type that may be proxied. 
        /// 
        /// 
        /// Member of the  to be examined.
        ///  
        /// 
        /// True if the member is compatible with lazy loading; otherwise false. 
        ///  
        /// 
        /// To be compatible with lazy loading, 
        /// a member must meet the criteria for being able to be proxied (defined elsewhere),
        /// and must be a navigation property.
        /// In addition, for relationships with a multiplicity of Many,
        /// the property type must be an implementation of ICollection<T>. 
        /// 
        internal static bool IsLazyLoadCandidate(EntityType ospaceEntityType, EdmMember member) 
        { 
            Debug.Assert(ospaceEntityType.DataSpace == DataSpace.OSpace, "ospaceEntityType.DataSpace must be OSpace");
 
            bool isCandidate = false;

            if (member.BuiltInTypeKind == BuiltInTypeKind.NavigationProperty)
            { 
                NavigationProperty navProperty = (NavigationProperty)member;
                RelationshipMultiplicity multiplicity = navProperty.ToEndMember.RelationshipMultiplicity; 
 
                PropertyInfo propertyInfo = EntityUtil.GetTopProperty(ospaceEntityType.ClrType, member.Name);
                Debug.Assert(propertyInfo != null, "Should have found lazy loading property"); 
                Type propertyValueType = propertyInfo.PropertyType;

                if (multiplicity == RelationshipMultiplicity.Many)
                { 
                    Type elementType;
                    isCandidate = EntityUtil.TryGetICollectionElementType(propertyValueType, out elementType); 
                } 
                else if (multiplicity == RelationshipMultiplicity.One || multiplicity == RelationshipMultiplicity.ZeroOrOne)
                { 
                    // This is an EntityReference property.
                    isCandidate = true;
                }
            } 

            return isCandidate; 
        } 

        ///  
        /// Method called by proxy interceptor delegate to provide lazy loading behavior for navigation properties.
        /// 
        /// property type
        /// The property value whose associated relationship is to be loaded. 
        /// String name of the relationship.
        /// String name of the related end to be loaded for the relationship specified by . 
        /// Entity wrapper object used to retrieve RelationshipManager for the proxied entity. 
        /// 
        /// True if the value instance was mutated and can be returned 
        /// False if the class should refetch the value because the instance has changed
        /// 
        private static bool LoadProperty(TItem propertyValue, string relationshipName, string targetRoleName, bool mustBeNull, object wrapperObject) where TItem : class
        { 
            // Only attempt to load collection if:
            // 
            // 1. Collection is non-null. 
            // 2. ObjectContext.ContextOptions.LazyLoadingEnabled is true
            // 3. A non-null RelationshipManager can be retrieved (this is asserted). 
            // 4. The EntityCollection is not already loaded.

            Debug.Assert(wrapperObject == null || wrapperObject is IEntityWrapper, "wrapperObject must be an IEntityWrapper");
            IEntityWrapper wrapper = (IEntityWrapper)wrapperObject; // We want an exception if the cast fails. 

            if (wrapper != null && wrapper.Context != null) 
            { 
                RelationshipManager relationshipManager = wrapper.RelationshipManager;
                Debug.Assert(relationshipManager != null, "relationshipManager should be non-null"); 
                if (relationshipManager != null && (!mustBeNull || propertyValue == null))
                {
                    RelatedEnd relatedEnd = relationshipManager.GetRelatedEndInternal(relationshipName, targetRoleName);
                    relatedEnd.DeferredLoad(); 
                }
            } 
 
            return propertyValue != null;
        } 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner       [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 

using System; 
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions; 
using System.Reflection;
using System.Reflection.Emit; 
using System.Security; 
using System.Security.Permissions;
using System.Data.Metadata.Edm; 
using System.Data.Objects.DataClasses;
using System.Collections;

namespace System.Data.Objects.Internal 
{
    ///  
    /// Defines and injects behavior into proxy class Type definitions 
    /// to allow navigation properties to lazily load their references or collection elements.
    ///  
    internal sealed class LazyLoadBehavior
    {
        /// 
        /// Return an expression tree that represents the actions required to load the related end 
        /// associated with the intercepted proxy member.
        ///  
        ///  
        /// EdmMember that specifies the member to be intercepted.
        ///  
        /// 
        /// PropertyInfo that specifies the CLR property to be intercepted.
        /// 
        ///  
        /// ParameterExpression that represents the proxy object.
        ///  
        ///  
        /// ParameterExpression that represents the proxied property value.
        ///  
        /// The Func that retrieves the wrapper from a proxy
        /// 
        /// Expression tree that encapsulates lazy loading behavior for the supplied member,
        /// or null if the expression tree could not be constructed. 
        /// 
        internal static Func GetInterceptorDelegate(EdmMember member, Func getEntityWrapperDelegate) 
            where TProxy : class 
            where TItem : class
        { 
            Func interceptorDelegate = (proxy, item) => true;

            Debug.Assert(member.BuiltInTypeKind == BuiltInTypeKind.NavigationProperty, "member should represent a navigation property");
            if (member.BuiltInTypeKind == BuiltInTypeKind.NavigationProperty) 
            {
                NavigationProperty navProperty = (NavigationProperty)member; 
                RelationshipMultiplicity multiplicity = navProperty.ToEndMember.RelationshipMultiplicity; 

                // Given the proxy and item parameters, construct one of the following expressions: 
                //
                // For collections:
                //  LazyLoadBehavior.LoadCollection(collection, "relationshipName", "targetRoleName", proxy._entityWrapperField)
                // 
                // For entity references:
                //  LazyLoadBehavior.LoadReference(item, "relationshipName", "targetRoleName", proxy._entityWrapperField) 
                // 
                // Both of these expressions return an object of the same type as the first parameter to LoadXYZ method.
                // In many cases, this will be the first parameter. 

                if (multiplicity == RelationshipMultiplicity.Many)
                {
                    interceptorDelegate = (proxy, item) => LoadProperty(item, 
                                                                               navProperty.RelationshipType.Identity,
                                                                               navProperty.ToEndMember.Identity, 
                                                                               false, 
                                                                               getEntityWrapperDelegate(proxy));
                } 
                else
                {
                    interceptorDelegate = (proxy, item) => LoadProperty(item,
                                                                               navProperty.RelationshipType.Identity, 
                                                                               navProperty.ToEndMember.Identity,
                                                                               true, 
                                                                               getEntityWrapperDelegate(proxy)); 
                }
            } 

            return interceptorDelegate;
        }
 
        /// 
        /// Determine if the specified member is compatible with lazy loading. 
        ///  
        /// 
        /// OSpace EntityType representing a type that may be proxied. 
        /// 
        /// 
        /// Member of the  to be examined.
        ///  
        /// 
        /// True if the member is compatible with lazy loading; otherwise false. 
        ///  
        /// 
        /// To be compatible with lazy loading, 
        /// a member must meet the criteria for being able to be proxied (defined elsewhere),
        /// and must be a navigation property.
        /// In addition, for relationships with a multiplicity of Many,
        /// the property type must be an implementation of ICollection<T>. 
        /// 
        internal static bool IsLazyLoadCandidate(EntityType ospaceEntityType, EdmMember member) 
        { 
            Debug.Assert(ospaceEntityType.DataSpace == DataSpace.OSpace, "ospaceEntityType.DataSpace must be OSpace");
 
            bool isCandidate = false;

            if (member.BuiltInTypeKind == BuiltInTypeKind.NavigationProperty)
            { 
                NavigationProperty navProperty = (NavigationProperty)member;
                RelationshipMultiplicity multiplicity = navProperty.ToEndMember.RelationshipMultiplicity; 
 
                PropertyInfo propertyInfo = EntityUtil.GetTopProperty(ospaceEntityType.ClrType, member.Name);
                Debug.Assert(propertyInfo != null, "Should have found lazy loading property"); 
                Type propertyValueType = propertyInfo.PropertyType;

                if (multiplicity == RelationshipMultiplicity.Many)
                { 
                    Type elementType;
                    isCandidate = EntityUtil.TryGetICollectionElementType(propertyValueType, out elementType); 
                } 
                else if (multiplicity == RelationshipMultiplicity.One || multiplicity == RelationshipMultiplicity.ZeroOrOne)
                { 
                    // This is an EntityReference property.
                    isCandidate = true;
                }
            } 

            return isCandidate; 
        } 

        ///  
        /// Method called by proxy interceptor delegate to provide lazy loading behavior for navigation properties.
        /// 
        /// property type
        /// The property value whose associated relationship is to be loaded. 
        /// String name of the relationship.
        /// String name of the related end to be loaded for the relationship specified by . 
        /// Entity wrapper object used to retrieve RelationshipManager for the proxied entity. 
        /// 
        /// True if the value instance was mutated and can be returned 
        /// False if the class should refetch the value because the instance has changed
        /// 
        private static bool LoadProperty(TItem propertyValue, string relationshipName, string targetRoleName, bool mustBeNull, object wrapperObject) where TItem : class
        { 
            // Only attempt to load collection if:
            // 
            // 1. Collection is non-null. 
            // 2. ObjectContext.ContextOptions.LazyLoadingEnabled is true
            // 3. A non-null RelationshipManager can be retrieved (this is asserted). 
            // 4. The EntityCollection is not already loaded.

            Debug.Assert(wrapperObject == null || wrapperObject is IEntityWrapper, "wrapperObject must be an IEntityWrapper");
            IEntityWrapper wrapper = (IEntityWrapper)wrapperObject; // We want an exception if the cast fails. 

            if (wrapper != null && wrapper.Context != null) 
            { 
                RelationshipManager relationshipManager = wrapper.RelationshipManager;
                Debug.Assert(relationshipManager != null, "relationshipManager should be non-null"); 
                if (relationshipManager != null && (!mustBeNull || propertyValue == null))
                {
                    RelatedEnd relatedEnd = relationshipManager.GetRelatedEndInternal(relationshipName, targetRoleName);
                    relatedEnd.DeferredLoad(); 
                }
            } 
 
            return propertyValue != null;
        } 
    }
}

// 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