/// <summary>
        /// Gets a <see cref="CodeTypeReference"/> for a CLR type.
        /// </summary>
        /// <param name="type">A CLR type.</param>
        /// <param name="codegenContext">A <see cref="ClientProxyGenerator"/>.</param>
        /// <param name="referencingType">The referencing type.</param>
        /// <returns>A <see cref="CodeTypeReference"/> for a CLR type.</returns>
        public static CodeTypeReference GetTypeReference(Type type, ICodeGenContext codegenContext, CodeTypeDeclaration referencingType)
        {
            if (type.IsPrimitive || type == typeof(void) || type == typeof(decimal) || type == typeof(string) || type == typeof(object))
            {
                return(new CodeTypeReference(type));
            }

            if (codegenContext != null && referencingType != null)
            {
                CodeNamespace ns = codegenContext.GetNamespace(referencingType);

                if (ns != null && !ns.Name.Equals(type.Namespace))
                {
                    // If the namespace is already imported, the following line will be a no-op.
                    ns.Imports.Add(new CodeNamespaceImport(type.Namespace));
                }
            }

            if (type.IsArray)
            {
                return(new CodeTypeReference(
                           CodeGenUtilities.GetTypeReference(type.GetElementType(), codegenContext, referencingType),
                           type.GetArrayRank()));
            }

            if (type.IsGenericType)
            {
                Type[] genericArguments           = type.GetGenericArguments();
                CodeTypeReference[] typeArguments = new CodeTypeReference[genericArguments.Length];
                for (int i = 0; i < genericArguments.Length; i++)
                {
                    typeArguments[i] = GetTypeReference(genericArguments[i]);
                }
                return(new CodeTypeReference(type.Name, typeArguments));
            }

            return(new CodeTypeReference(type.Name));
        }
        /// <summary>
        /// Gets a <see cref="CodeTypeReference"/> for a CLR type.
        /// </summary>
        /// <param name="type">A CLR type.</param>
        /// <param name="codegenContext">A <see cref="ClientProxyGenerator"/>.</param>
        /// <param name="referencingType">The referencing type.</param>
        /// <returns>A <see cref="CodeTypeReference"/> for a CLR type.</returns>
        public static CodeTypeReference GetTypeReference(Type type, ICodeGenContext codegenContext, CodeTypeDeclaration referencingType)
        {
            if (type.IsPrimitive || type == typeof(void) || type == typeof(decimal) || type == typeof(string) || type == typeof(object))
            {
                return new CodeTypeReference(type);
            }

            if (codegenContext != null && referencingType != null)
            {
                CodeNamespace ns = codegenContext.GetNamespace(referencingType);

                if (ns != null && !ns.Name.Equals(type.Namespace))
                {
                    // If the namespace is already imported, the following line will be a no-op.
                    ns.Imports.Add(new CodeNamespaceImport(type.Namespace));
                }
            }

            if (type.IsArray)
            {
                return new CodeTypeReference(
                    CodeGenUtilities.GetTypeReference(type.GetElementType(), codegenContext, referencingType),
                    type.GetArrayRank());
            }

            if (type.IsGenericType)
            {
                Type[] genericArguments = type.GetGenericArguments();
                CodeTypeReference[] typeArguments = new CodeTypeReference[genericArguments.Length];
                for (int i = 0; i < genericArguments.Length; i++)
                {
                    typeArguments[i] = GetTypeReference(genericArguments[i]);
                }
                return new CodeTypeReference(type.Name, typeArguments);
            }

            return new CodeTypeReference(type.Name);
        }
        /// <summary>
        /// Generates the GetEntityState helper method that allows POCO types to retrieve their
        /// entity state from the contect.  It is not available on the POCO types directly.
        /// </summary>
        /// <param name="codeGenContext">The context in which we are generating code.</param>
        /// <param name="businessLogicClass">The class we are generating.</param>
        /// <returns>The <see cref="CodeTypeMember"/> containing the helper method.</returns>
        private static CodeTypeMember GenerateGetEntityState(ICodeGenContext codeGenContext, CodeTypeDeclaration businessLogicClass)
        {
            // Add an import for System.Data.Objects
            CodeNamespace codeNamespace = codeGenContext.GetNamespace(businessLogicClass);
            if (codeNamespace != null)
            {
                codeNamespace.Imports.Add(new CodeNamespaceImport("System.Data.Objects"));
            }

            //private EntityState GetEntityState(object entity)
            //{
            //    ObjectStateEntry stateEntry = null;
            //    if (!this.ObjectContext.ObjectStateManager.TryGetObjectStateEntry(entity, out stateEntry))
            //    {
            //        return EntityState.Detached;
            //    }
            //    return stateEntry.State;
            //}

            // Declaration
            CodeMemberMethod method = new CodeMemberMethod();
            method.Name = LinqToEntitiesContext.GetEntityStateHelperMethodName;
            method.ReturnType = new CodeTypeReference(typeof(EntityState).Name);
            method.Attributes = MemberAttributes.Private;
            method.Parameters.Add(new CodeParameterDeclarationExpression(typeof(object), "entity"));

            // ObjectStateEntry stateEntry = null;
            method.Statements.Add(new CodeVariableDeclarationStatement("ObjectStateEntry", "stateEntry", new CodePrimitiveExpression(null)));

            CodeArgumentReferenceExpression entityArgRef = new CodeArgumentReferenceExpression("entity");
            CodeExpression contextRef = new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "ObjectContext");

            CodeFieldReferenceExpression detachedStateRef = new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(typeof(EntityState).Name), Enum.GetName(typeof(EntityState), EntityState.Detached));
            CodePropertyReferenceExpression objectStateMgrRef = new CodePropertyReferenceExpression(contextRef, "ObjectStateManager");

            CodeVariableReferenceExpression entityStateRef = new CodeVariableReferenceExpression("stateEntry");

            // The "_out_" prefix will be replaced below with the language-appropriate modifier to make an out param.
            // CodeDom does not support this, so we must do some string manipulation
            CodeVariableReferenceExpression outEntityStateRef = new CodeVariableReferenceExpression("_out_stateEntry");

            // this.ObjectContext.ObjectStateManager.TryGetObjectStateEntry(entity, out stateEntry)
            CodeMethodInvokeExpression getObjectStateEntryCall = new CodeMethodInvokeExpression(objectStateMgrRef, "TryGetObjectStateEntry", entityArgRef, outEntityStateRef);

            // if (...TryGet())
            CodeExpression tryGetTest = CodeGenUtilities.MakeEqual(typeof(bool), getObjectStateEntryCall, new CodePrimitiveExpression(false), codeGenContext.IsCSharp);

            // if (...TryGet..) { return EntityState.Detached; }
            CodeMethodReturnStatement returnDetached = new CodeMethodReturnStatement(detachedStateRef);
            CodeConditionStatement ifTryGet = new CodeConditionStatement(tryGetTest, returnDetached);
            method.Statements.Add(ifTryGet);

            // Return entityState.State;
            method.Statements.Add(new CodeMethodReturnStatement(new CodePropertyReferenceExpression(entityStateRef, "State")));

            // CodeDom does not support specifying 'out' parameters at the method call site.
            // So convert the entire method into a snippet of text

            StringBuilder snippet = null;
            CodeDomProvider provider = codeGenContext.Provider;
            using (StringWriter snippetWriter = new StringWriter(System.Globalization.CultureInfo.CurrentCulture))
            {
                provider.GenerateCodeFromMember(method, snippetWriter, codeGenContext.CodeGeneratorOptions);
                snippet = snippetWriter.GetStringBuilder();
            }

            // Our convention above is that "_out_" will be replaced by the language-appropriate "out" parameter modifier.
            // In the case of VB, it is the default
            snippet.Replace("_out_", codeGenContext.IsCSharp ? "out " : string.Empty);

            // We need to indent the entire snippet 2 levels
            string indent = codeGenContext.CodeGeneratorOptions.IndentString;
            indent += indent;

            string snippetText = indent + snippet.ToString().Replace(Environment.NewLine, Environment.NewLine + indent).TrimEnd(' ');
            CodeSnippetTypeMember methodAsText = new CodeSnippetTypeMember(snippetText);

            return methodAsText;
        }
        /// <summary>
        /// Generates the GetEntityState helper method that allows POCO types to retrieve their
        /// entity state from the contect.  It is not available on the POCO types directly.
        /// </summary>
        /// <param name="codeGenContext">The context in which we are generating code.</param>
        /// <param name="businessLogicClass">The class we are generating.</param>
        /// <returns>The <see cref="CodeTypeMember"/> containing the helper method.</returns>
        private static CodeTypeMember GenerateGetEntityState(ICodeGenContext codeGenContext, CodeTypeDeclaration businessLogicClass)
        {
            // Add an import for System.Data.Objects
            CodeNamespace codeNamespace = codeGenContext.GetNamespace(businessLogicClass);

            if (codeNamespace != null)
            {
                codeNamespace.Imports.Add(new CodeNamespaceImport("System.Data.Objects"));
            }

            //private EntityState GetEntityState(object entity)
            //{
            //    ObjectStateEntry stateEntry = null;
            //    if (!this.ObjectContext.ObjectStateManager.TryGetObjectStateEntry(entity, out stateEntry))
            //    {
            //        return EntityState.Detached;
            //    }
            //    return stateEntry.State;
            //}

            // Declaration
            CodeMemberMethod method = new CodeMemberMethod();

            method.Name       = LinqToEntitiesContext.GetEntityStateHelperMethodName;
            method.ReturnType = new CodeTypeReference(typeof(EntityState).Name);
            method.Attributes = MemberAttributes.Private;
            method.Parameters.Add(new CodeParameterDeclarationExpression(typeof(object), "entity"));

            // ObjectStateEntry stateEntry = null;
            method.Statements.Add(new CodeVariableDeclarationStatement("ObjectStateEntry", "stateEntry", new CodePrimitiveExpression(null)));

            CodeArgumentReferenceExpression entityArgRef = new CodeArgumentReferenceExpression("entity");
            CodeExpression contextRef = new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "ObjectContext");

            CodeFieldReferenceExpression    detachedStateRef  = new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(typeof(EntityState).Name), Enum.GetName(typeof(EntityState), EntityState.Detached));
            CodePropertyReferenceExpression objectStateMgrRef = new CodePropertyReferenceExpression(contextRef, "ObjectStateManager");

            CodeVariableReferenceExpression entityStateRef = new CodeVariableReferenceExpression("stateEntry");

            // The "_out_" prefix will be replaced below with the language-appropriate modifier to make an out param.
            // CodeDom does not support this, so we must do some string manipulation
            CodeVariableReferenceExpression outEntityStateRef = new CodeVariableReferenceExpression("_out_stateEntry");

            // this.ObjectContext.ObjectStateManager.TryGetObjectStateEntry(entity, out stateEntry)
            CodeMethodInvokeExpression getObjectStateEntryCall = new CodeMethodInvokeExpression(objectStateMgrRef, "TryGetObjectStateEntry", entityArgRef, outEntityStateRef);

            // if (...TryGet())
            CodeExpression tryGetTest = CodeGenUtilities.MakeEqual(typeof(bool), getObjectStateEntryCall, new CodePrimitiveExpression(false), codeGenContext.IsCSharp);

            // if (...TryGet..) { return EntityState.Detached; }
            CodeMethodReturnStatement returnDetached = new CodeMethodReturnStatement(detachedStateRef);
            CodeConditionStatement    ifTryGet       = new CodeConditionStatement(tryGetTest, returnDetached);

            method.Statements.Add(ifTryGet);

            // Return entityState.State;
            method.Statements.Add(new CodeMethodReturnStatement(new CodePropertyReferenceExpression(entityStateRef, "State")));

            // CodeDom does not support specifying 'out' parameters at the method call site.
            // So convert the entire method into a snippet of text

            StringBuilder   snippet  = null;
            CodeDomProvider provider = codeGenContext.Provider;

            using (StringWriter snippetWriter = new StringWriter(System.Globalization.CultureInfo.CurrentCulture))
            {
                provider.GenerateCodeFromMember(method, snippetWriter, codeGenContext.CodeGeneratorOptions);
                snippet = snippetWriter.GetStringBuilder();
            }

            // Our convention above is that "_out_" will be replaced by the language-appropriate "out" parameter modifier.
            // In the case of VB, it is the default
            snippet.Replace("_out_", codeGenContext.IsCSharp ? "out " : string.Empty);

            // We need to indent the entire snippet 2 levels
            string indent = codeGenContext.CodeGeneratorOptions.IndentString;

            indent += indent;

            string snippetText = indent + snippet.ToString().Replace(Environment.NewLine, Environment.NewLine + indent).TrimEnd(' ');
            CodeSnippetTypeMember methodAsText = new CodeSnippetTypeMember(snippetText);

            return(methodAsText);
        }