Ejemplo n.º 1
0
        /// <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(CodeGenContext 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.Entity.Core.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>
 /// Tests whether the given class name is a legal identifier for the current language.
 /// </summary>
 /// <remarks>
 /// This test will invoke <see cref="ReportException"/> with an <see cref="ArgumentException"/>
 /// if the class name is not a legal identifier.
 /// </remarks>
 /// <param name="className">String to test for legality</param>
 private void ValidateClassName(string className)
 {
     using (CodeGenContext codeGenContext = new CodeGenContext(this.Language, this.RootNamespace))
     {
         if (string.IsNullOrEmpty(className) || !codeGenContext.IsValidIdentifier(className))
         {
             this.ReportException(new ArgumentException(String.Format(CultureInfo.CurrentCulture, Resources.BusinessLogicClass_Error_Invalid_ClassName, className)));
         }
     }
 }
Ejemplo n.º 3
0
        /// <summary>
        /// Creates the entire business logic class within the specified namespace name
        /// </summary>
        /// <param name="codeGenContext">The context into which to generate code.  It cannot be null.</param>
        /// <param name="className">The name of the class to generate.  It cannot be null or empty.</param>
        /// <param name="namespaceName">The namespace to use for the generated code.  It cannot be empty.</param>
        protected void GenerateBusinessLogicClass(CodeGenContext codeGenContext, string className, string namespaceName)
        {
            if (codeGenContext == null)
            {
                throw new ArgumentNullException("codeGenContext");
            }
            if (string.IsNullOrEmpty(className))
            {
                throw new ArgumentNullException("className");
            }
            if (string.IsNullOrEmpty(namespaceName))
            {
                throw new ArgumentNullException("namespaceName");
            }

            // namespace XXX { }
            CodeNamespace ns = codeGenContext.GetOrGenNamespace(namespaceName);

            // public class $classname$ { }
            CodeTypeDeclaration businessLogicClass = this.CreateBusinessLogicClass(codeGenContext, ns, className);

            ns.Types.Add(businessLogicClass);

            // Class-level Xml comments
            // Empty class gets its own comment because it has no ContextType to describe
            string remarksComment;

            if (this.ContextType == null)
            {
                remarksComment = Resources.BusinessLogicClass_Class_Remarks_Empty;
            }
            else
            {
                remarksComment = String.Format(CultureInfo.CurrentCulture, Resources.BusinessLogicClass_Class_Remarks, this.ContextType.Name);
            }

            // Add developer comment explaining what this class does
            businessLogicClass.Comments.Add(new CodeCommentStatement(remarksComment, false));

            // Add [RequiresAuthentication] as a comment
            if (this.ContextType != null)
            {
                remarksComment = codeGenContext.IsCSharp
                                    ? Resources.BusinessLogicClass_RequiresAuthentication_CSharp
                                    : Resources.BusinessLogicClass_RequiresAuthentication_VB;
                businessLogicClass.Comments.Add(new CodeCommentStatement(remarksComment, false));
            }

            if (this.IsClientAccessEnabled)
            {
                // [EnableClientAccess]
                CodeAttributeDeclaration attr = CodeGenUtilities.CreateAttributeDeclaration(BusinessLogicClassConstants.EnableClientAccessAttributeTypeName);
                businessLogicClass.CustomAttributes.Add(attr);
            }
            else
            {
                // if not enabled, add a comment explaining how to enable it
                businessLogicClass.Comments.Add(new CodeCommentStatement(Resources.BusinessLogicClass_EnableClientAccess_Comment));
            }

            // Gen all domain operation entries
            // Sort by name for baseline predictability
            foreach (BusinessLogicEntity entity in this.Entities.OrderBy(e => e.Name))
            {
                if (entity.IsIncluded)
                {
                    // Add an import for this entity's namespace if needed
                    // This is necessary only when entities exist in a different namespace from the context
                    CodeGenUtilities.AddImportIfNeeded(ns, entity.ClrType.Namespace);

                    this.GenerateEntityDomainOperationEntries(codeGenContext, businessLogicClass, entity);
                }
            }

            // If any private helper methods were generated, append them now.
            // We sort by their keys to give baseline predictability.
            Dictionary <string, CodeTypeMember> helpers = BusinessLogicContext.GetHelperMemberDictionary(businessLogicClass);

            foreach (string key in helpers.Keys.OrderBy(s => s))
            {
                businessLogicClass.Members.Add(helpers[key]);
            }

            // If we exposed an OData endpoint, add a reference to the OData assembly
            // so it appears in the server project, allowing the user to chose
            // CopyLocal=true for bin deploy scenarios
            if (this.IsODataEndpointEnabled)
            {
                codeGenContext.AddReference(typeof(ODataEndpointFactory).Assembly.FullName);
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Generates the delete domain operation entry
        /// </summary>
        /// <param name="codeGenContext">The context to use</param>
        /// <param name="businessLogicClass">The business logic class into which to generate it</param>
        /// <param name="entity">The entity for which to generate the method</param>
        protected override void GenerateDeleteMethod(CodeGenContext codeGenContext, CodeTypeDeclaration businessLogicClass, BusinessLogicEntity entity)
        {
            string parameterName = CodeGenUtilities.MakeLegalParameterName(entity.Name);

            // public void Delete$EntityName$($entityType$ $entityName$)
            CodeMemberMethod method = new CodeMemberMethod();

            businessLogicClass.Members.Add(method);

            //LinqToEntitiesEntity efEntity = (LinqToEntitiesEntity)entity;
            method.Name       = "Delete" + CodeGenUtilities.MakeLegalEntityName(entity.Name);
            method.Attributes = MemberAttributes.Public | MemberAttributes.Final;   // final needed to prevent virtual

            // parameter declaration
            method.Parameters.Add(new CodeParameterDeclarationExpression(entity.ClrType.Name, parameterName));

            // if ($entity$.EntityState != EntityState.Detached)
            // {
            //      ObjectContext.ObjectStateManager.ChangeObjectState($entity$, EntityState.Deleted);
            // }
            // else
            // {
            //      ObjectContext.Products.Attach($entity$);
            //      ObjectContext.Products.DeleteObject($entity$);
            // }
            //
            // In the case of POCO objects, we use "this.GetEntityState(entity)"
            // rather than referring to the entity's EntityState property

            LinqToEntitiesEntity            efEntity   = (LinqToEntitiesEntity)entity;
            CodeArgumentReferenceExpression entityExpr = new CodeArgumentReferenceExpression(parameterName);

            // If this is a POCO class, we need to generate a call to a helper method to get
            // the EntityState, otherwise we can directly de-reference it on the entity
            // If this entity does not have an EntityState member, we need to use a helper method instead.
            // This call tells us whether we need this helper and, if so, generates it.
            bool useGetEntityStateHelper = LinqToEntitiesContext.GenerateGetEntityStateIfNecessary(codeGenContext, businessLogicClass, entity);

            CodeExpression getEntityStateExpr;

            if (useGetEntityStateHelper)
            {
                // this.GetEntityState($entity$)...
                getEntityStateExpr = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), LinqToEntitiesContext.GetEntityStateHelperMethodName, entityExpr);
            }
            else
            {
                // $entity$.EntityState...
                getEntityStateExpr = new CodePropertyReferenceExpression(entityExpr, LinqToEntitiesContext.EntityStatePropertyName);
            }

            CodeExpression contextRef = new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "ObjectContext");
            CodePropertyReferenceExpression objectSetRef     = new CodePropertyReferenceExpression(contextRef, efEntity.DefaultObjectSetName);
            CodeFieldReferenceExpression    detachedStateRef = new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(typeof(EntityState).Name), Enum.GetName(typeof(EntityState), EntityState.Detached));
            CodeExpression equalTest = CodeGenUtilities.MakeNotEqual(typeof(EntityState), getEntityStateExpr, detachedStateRef, codeGenContext.IsCSharp);

            CodeFieldReferenceExpression    deletedStateRef   = new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(typeof(EntityState).Name), Enum.GetName(typeof(EntityState), EntityState.Deleted));
            CodePropertyReferenceExpression objectStateMgrRef = new CodePropertyReferenceExpression(contextRef, "ObjectStateManager");
            CodeMethodInvokeExpression      changeStateExpr   = new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(objectStateMgrRef, "ChangeObjectState"), entityExpr, deletedStateRef);

            CodeStatement[] trueStatements = new CodeStatement[] { new CodeExpressionStatement(changeStateExpr) };

            CodeMethodInvokeExpression attachCall = new CodeMethodInvokeExpression(objectSetRef, "Attach", entityExpr);
            CodeMethodInvokeExpression deleteCall = new CodeMethodInvokeExpression(objectSetRef, "DeleteObject", entityExpr);

            CodeStatement[] falseStatements = new CodeStatement[] { new CodeExpressionStatement(attachCall), new CodeExpressionStatement(deleteCall) };

            CodeConditionStatement ifStmt = new CodeConditionStatement(equalTest, trueStatements, falseStatements);

            method.Statements.Add(ifStmt);
        }
Ejemplo n.º 5
0
 /// <summary>
 /// Generates additional metadata classes for the given entity if necessary.
 /// </summary>
 /// <param name="codeGenContext">The context to use to generate code.</param>
 /// <param name="optionalSuffix">If not null, optional suffix to class name and namespace</param>
 /// <param name="entity">The entity for which to generate the additional metadata.</param>
 /// <returns><c>true</c> means at least some code was generated.</returns>
 /// <remarks>
 /// This default implementation of the virtual method does not generate any additional classes. It needs to be overridden in the derived
 /// classes to generate additional metadata classes if necessary.
 /// </remarks>
 protected virtual bool GenerateAdditionalMetadataClasses(CodeGenContext codeGenContext, string optionalSuffix, BusinessLogicEntity entity)
 {
     return(false);
 }
Ejemplo n.º 6
0
        /// <summary>
        /// Generates the metadata class for the given object (entity or complex object)
        /// </summary>
        /// <param name="codeGenContext">The context to use to generate code.</param>
        /// <param name="optionalSuffix">If not null, optional suffix to class name and namespace</param>
        /// <param name="type">The type of the object for which to generate the metadata class.</param>
        /// <returns><c>true</c> means at least some code was generated.</returns>
        public bool GenerateMetadataClass(CodeGenContext codeGenContext, string optionalSuffix, Type type)
        {
            // If already have a buddy class, bypass all this logic
            // Use soft dependency (string name) to avoid static dependency on DataAnnotations.
            // We do this because this wizard must run from the GAC, and DataAnnotations will not necessarily be in the GAC too.
            Type buddyClassType = TypeUtilities.GetAssociatedMetadataType(type);

            if (buddyClassType != null)
            {
                return(false);
            }

            string className      = type.Name;
            string classNamespace = type.Namespace;

            bool addSuffix = !string.IsNullOrEmpty(optionalSuffix);

            if (addSuffix)
            {
                className      += optionalSuffix;
                classNamespace += optionalSuffix;
            }

            // Every object could have a unique namespace (odd, but true)
            // So we logically create a new namespace for each object.  Those
            // sharing a namespace will reuse the CodeNamespace.
            // We allow the caller to specify in case it needs to override that
            // namespace.  Unit testing is such a scenario
            CodeNamespace codeNamespace = codeGenContext.GetOrGenNamespace(classNamespace);

            // If we redirected to a different namespace than the object, import the real object's namespace
            if (addSuffix)
            {
                CodeGenUtilities.AddImportIfNeeded(codeNamespace, type.Namespace);
            }

            // Name of buddy class is $objectClassName$Metadata (e.g. Orders --> OrdersMetadata)
            string buddyClassName = className + "Metadata";

            // We use the full outer.inner type naming convention for VB because they cannot resolve it otherwise.
            // C# can currently resolve it due to a bug in the compiler, but it is safer to use the legal syntax here.
            string fullBuddyClassName = className + "." + buddyClassName;

            CodeTypeDeclaration objectClass = null;

            // public class $objectType$ { }
            objectClass                = CodeGenUtilities.CreateTypeDeclaration(className, classNamespace);
            objectClass.IsPartial      = true;
            objectClass.TypeAttributes = TypeAttributes.Public;

            // Add explanatory comments about what the [MetadataTypeAttribute] does
            objectClass.Comments.Add(new CodeCommentStatement(String.Format(CultureInfo.CurrentCulture, Resources.BusinessLogicClass_Entity_Partial_Class_Remarks, buddyClassName, className), false));

            // [MetadataType(typeof($objectType$.$objectType$_Metadata))]
            CodeAttributeDeclaration attr = CodeGenUtilities.CreateAttributeDeclaration(BusinessLogicClassConstants.MetadataTypeAttributeTypeName);

            CodeAttributeArgument attrArg = new CodeAttributeArgument(new CodeTypeOfExpression(fullBuddyClassName));

            attr.Arguments.Add(attrArg);
            objectClass.CustomAttributes.Add(attr);

            // public sealed class $objectType$_Metadata { }
            // (note: cannot set 'static' modified from CodeDom.)
            CodeTypeDeclaration buddyClass = CodeGenUtilities.CreateTypeDeclaration(buddyClassName, classNamespace);

            // Both VB and C# use a friend/public buddy class.  A private buddy class does not
            // compile in VB, and it compiles in C# only due to a bug.
            buddyClass.TypeAttributes = TypeAttributes.Sealed | TypeAttributes.NestedAssembly;
            bool generatedProperty = false;

            // Generate a developer comment describing what this class does
            buddyClass.Comments.Add(new CodeCommentStatement(String.Format(CultureInfo.CurrentCulture, Resources.Buddy_Class_Remarks, type.Name)));

            // Add a language-specific example
            string explanation = codeGenContext.IsCSharp ? Resources.Buddy_Class_Remarks_CSharp : Resources.Buddy_Class_Remarks_VB;

            buddyClass.Comments.Add(new CodeCommentStatement(explanation, false));

            // Generate a private ctor to make it impossible to instantiate this class
            CodeConstructor ctor = new CodeConstructor();

            ctor.Attributes = MemberAttributes.Private;
            ctor.Comments.Add(new CodeCommentStatement(Resources.BusinessLogicClass_Private_Ctor_Comment));
            buddyClass.Members.Add(ctor);

            // Sort by name order for baseline predictability
            foreach (PropertyInfo propertyInfo in type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly).OrderBy(p => p.Name))
            {
                // CodeDom does not support auto-implemented properties, so we will generate fields and then transform them into properties
                Type propType = propertyInfo.PropertyType;
                if (propType.IsVisible && propertyInfo.GetGetMethod() != null && this.CanGeneratePropertyOfType(propType))
                {
                    // Add an import for this property type's namespace if needed
                    CodeGenUtilities.AddImportIfNeeded(codeNamespace, propertyInfo.PropertyType.Namespace);

                    CodeSnippetTypeMember property = CodeGenUtilities.CreateAutomaticPropertyDeclaration(codeGenContext, buddyClass, propertyInfo, !string.IsNullOrEmpty(codeNamespace.Name) /* insideNamespace */);

                    buddyClass.Members.Add(property);
                    generatedProperty = true;
                }
            }

            // Don't generate anything if the buddy class is empty
            if (generatedProperty)
            {
                // Add the partial object class to the namespace
                codeNamespace.Types.Add(objectClass);

                // Add the metadata class as a nested class inside the partial object class
                objectClass.Members.Add(buddyClass);
            }

            // false if no properties were generated, indicating no code should be emitted
            return(generatedProperty);
        }
Ejemplo n.º 7
0
 /// <summary>
 /// Creates the "delete" method for the entity
 /// </summary>
 /// <param name="codeGenContext">The context into which to generate code.  It cannot be null.</param>
 /// <param name="businessLogicClass">The class into which to generate the method</param>
 /// <param name="entity">The entity which will be affected by this method</param>
 protected virtual void GenerateDeleteMethod(CodeGenContext codeGenContext, CodeTypeDeclaration businessLogicClass, BusinessLogicEntity entity)
 {
 }
Ejemplo n.º 8
0
 /// <summary>
 /// Creates the "select" domain operation entry for the entity
 /// </summary>
 /// <remarks>This base class unconditionally returns <c>null</c> and should not be called by derived classes.
 /// This allows the base class to be used for the blank <see cref="DomainService"/>.</remarks>
 /// <param name="codeGenContext">The context into which to generate code.  It cannot be null.</param>
 /// <param name="businessLogicClass">The class into which to generate the method</param>
 /// <param name="entity">The entity which will be affected by this method</param>
 /// <returns>The newly created method</returns>
 protected virtual CodeMemberMethod GenerateSelectMethod(CodeGenContext codeGenContext, CodeTypeDeclaration businessLogicClass, BusinessLogicEntity entity)
 {
     return(null);
 }
        /// <summary>
        /// Creates the entire business logic class within the specified namespace name
        /// </summary>
        /// <param name="codeGenContext">The context into which to generate code.  It cannot be null.</param>
        /// <param name="className">The name of the class to generate.  It cannot be null or empty.</param>
        /// <param name="namespaceName">The namespace to use for the generated code.  It cannot be empty.</param>
        protected void GenerateBusinessLogicClass(CodeGenContext codeGenContext, string className, string namespaceName)
        {
            if (codeGenContext == null)
            {
                throw new ArgumentNullException("codeGenContext");
            }
            if (string.IsNullOrEmpty(className))
            {
                throw new ArgumentNullException("className");
            }
            if (string.IsNullOrEmpty(namespaceName))
            {
                throw new ArgumentNullException("namespaceName");
            }

            // namespace XXX { }
            CodeNamespace ns = codeGenContext.GetOrGenNamespace(namespaceName);

            // public class $classname$ { }
            CodeTypeDeclaration businessLogicClass = this.CreateBusinessLogicClass(codeGenContext, ns, className);
            ns.Types.Add(businessLogicClass);

            // Class-level Xml comments
            // Empty class gets its own comment because it has no ContextType to describe
            string remarksComment;
            if (this.ContextType == null)
            {
                remarksComment = Resources.BusinessLogicClass_Class_Remarks_Empty;
            }
            else
            {
                remarksComment = String.Format(CultureInfo.CurrentCulture, Resources.BusinessLogicClass_Class_Remarks, this.ContextType.Name);
            }

            // Add developer comment explaining what this class does
            businessLogicClass.Comments.Add(new CodeCommentStatement(remarksComment, false));

            // Add [RequiresAuthentication] as a comment
            if (this.ContextType != null)
            {
                remarksComment = codeGenContext.IsCSharp
                                    ? Resources.BusinessLogicClass_RequiresAuthentication_CSharp
                                    : Resources.BusinessLogicClass_RequiresAuthentication_VB;
                businessLogicClass.Comments.Add(new CodeCommentStatement(remarksComment, false));
            }

            if (this.IsClientAccessEnabled)
            {
                // [EnableClientAccess]
                CodeAttributeDeclaration attr = CodeGenUtilities.CreateAttributeDeclaration(BusinessLogicClassConstants.EnableClientAccessAttributeTypeName);
                businessLogicClass.CustomAttributes.Add(attr);
            }
            else
            {
                // if not enabled, add a comment explaining how to enable it
                businessLogicClass.Comments.Add(new CodeCommentStatement(Resources.BusinessLogicClass_EnableClientAccess_Comment));
            }

            // Gen all domain operation entries
            // Sort by name for baseline predictability
            foreach (BusinessLogicEntity entity in this.Entities.OrderBy(e => e.Name))
            {
                if (entity.IsIncluded)
                {
                    // Add an import for this entity's namespace if needed
                    // This is necessary only when entities exist in a different namespace from the context
                    CodeGenUtilities.AddImportIfNeeded(ns, entity.ClrType.Namespace);

                    this.GenerateEntityDomainOperationEntries(codeGenContext, businessLogicClass, entity);
                }
            }

            // If any private helper methods were generated, append them now.
            // We sort by their keys to give baseline predictability.
            Dictionary<string, CodeTypeMember> helpers = BusinessLogicContext.GetHelperMemberDictionary(businessLogicClass);
            foreach (string key in helpers.Keys.OrderBy(s => s))
            {
                businessLogicClass.Members.Add(helpers[key]);
            }

            // If we exposed an OData endpoint, add a reference to the OData assembly
            // so it appears in the server project, allowing the user to chose 
            // CopyLocal=true for bin deploy scenarios
            if (this.IsODataEndpointEnabled)
            {
                codeGenContext.AddReference(typeof(ODataEndpointFactory).Assembly.FullName);
            }
        }
        /// <summary>
        /// Generates the code for the domain service class.
        /// </summary>
        /// <param name="language">The language to use.</param>
        /// <param name="rootNamespace">The root namespace (VB).</param>
        /// <param name="optionalSuffix">If nonblank, the suffix to append to namespace and class names for testing</param>
        /// <returns>A value containing the generated source code and necessary references.</returns>
        public IGeneratedCode GenerateMetadataClasses(string language, string rootNamespace, string optionalSuffix)
        {
            using (CodeGenContext codeGenContext = new CodeGenContext(language, rootNamespace))
            {
                bool generatedAnyCode = this.GenerateMetadataClasses(codeGenContext, optionalSuffix);
                if (generatedAnyCode)
                {
                    IGeneratedCode generatedCode = codeGenContext.GenerateCode();
                    return generatedCode;
                }
            }

            // Did not generate any code -- return empty tuple
            return new GeneratedCode();
        }
 /// <summary>
 /// Generates the code for the domain service class.
 /// </summary>
 /// <param name="language">The language to use.</param>
 /// <param name="className">The name of the class.</param>
 /// <param name="namespaceName">The namespace to use for the class.</param>
 /// <param name="rootNamespace">The root namespace (VB).</param>
 /// <returns>A value containing the generated source code and necessary references.</returns>
 public IGeneratedCode GenerateBusinessLogicClass(string language, string className, string namespaceName, string rootNamespace)
 {
     using (CodeGenContext codeGenContext = new CodeGenContext(language, rootNamespace))
     {
         this.GenerateBusinessLogicClass(codeGenContext, className, namespaceName);
         return codeGenContext.GenerateCode();
     }
 }