EntityViewGenerator.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / ndp / fx / src / DataEntityDesign / Design / System / Data / Entity / Design / EntityViewGeneration / EntityViewGenerator.cs / 1 / EntityViewGenerator.cs

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

using System; 
using System.CodeDom;
using System.CodeDom.Compiler;
using System.IO;
using System.Collections.Generic; 
using System.Text;
using System.Data; 
using System.Data.SqlClient; 
using System.Data.Metadata.Edm;
using System.Data.Mapping; 
using System.Data.EntityClient;
using System.Data.EntityModel;
using System.Data.Common.CommandTrees;
using System.Reflection; 
using System.Security.Cryptography;
using System.Data.Entity.Design.Common; 
using System.Diagnostics; 
using System.Globalization;
using System.Data.Common.Utils; 

namespace System.Data.Entity.Design
{
    ///  
    /// EntityViewGenerator class produces the views for the extents in the passed in StorageMappingItemCollection.
    /// The views are written as code to the passed in output stream. There are a set of options that user 
    /// can use to control the code generation process. The options should be apssed into the constrcutor. 
    /// While storing the views in the code, the view generator class also stores a Hash value produced based
    /// on the content of the views and the names of extents. We also generate a hash for each schema file( csdl, ssdl and msl) 
    /// that was used in view generation process and store the hash in the generated code.The entity runtime will try to discover this
    /// type and if it does discover it will use the generated views in this type. The discovery process is
    /// explained in detail in the comments for StorageMappingItemCollection class.
    /// The runtime will throw an exception if any of the the hash values produced in the design time does not match 
    /// the hash values produced at the runtime.
    ///  
    public class EntityViewGenerator 
    {
        #region Constructors 
        /// 
        /// Create the instance of ViewGenerator with the given language option.
        /// 
        /// Language Option for generated code. 
        public EntityViewGenerator(LanguageOption languageOption)
        { 
            m_languageOption = EDesignUtil.CheckLanguageOptionArgument(languageOption, "languageOption"); 
        }
 
        /// 
        /// Create the instance of ViewGenerator using C# as the default
        /// language option.
        ///  
        public EntityViewGenerator()
            : this(LanguageOption.GenerateCSharpCode) 
        { 
        }
 
        #endregion

        #region Fields
        private LanguageOption m_languageOption; 
        #endregion
 
        #region Properties 
        /// 
        /// Language Option for generated code. 
        /// 
        public LanguageOption LanguageOption
        {
            get { return m_languageOption; } 
            set { m_languageOption = EDesignUtil.CheckLanguageOptionArgument(value, "value"); }
        } 
        #endregion 

        #region Methods 
        /// 
        /// Generates the views for the extents in the mapping item collection and produces
        /// the code for a type that will cache these views. The methods also produces
        /// a hash based on the StorageEntityContainerMapping, which contains all the 
        /// metadata and mapping. It also produces a hash based
        /// on the view content and the name of the extents. 
        ///  
        /// Mapping Item Collection for which views should be generated
        /// Uri to which generated code needs to be written 
        public IList GenerateViews(StorageMappingItemCollection mappingCollection, string outputPath)
        {
            EDesignUtil.CheckStringArgument(outputPath, "outputPath");
 
            CodeDomProvider provider;
            IList schemaErrors; 
            Dictionary generatedViews; 
            if (GetViewsWithErrors(mappingCollection, out provider, out schemaErrors, out generatedViews))
            { 
                return schemaErrors;
            }

            //Create a stream over the output URI to write the generated code 
            using (StreamWriter outputWriter = new System.IO.StreamWriter(outputPath))
            { 
                GenerateAndStoreViews(mappingCollection, generatedViews, 
                    outputWriter, provider, schemaErrors);
            } 
            return schemaErrors;
        }

        ///  
        /// Generates the views for the extents in the mapping item collection and produces
        /// the code for a type that will cache these views. The methods also produces 
        /// a hash based on the storageEntityContainerMapping object, which contains all the 
        /// metadata and mapping. It also produces a hash based
        /// on the view content and the name of the extents. 
        /// 
        /// Mapping Item Collection for which views should be generated
        /// Output writer to which we want to write the code
        public IList GenerateViews(StorageMappingItemCollection mappingCollection, TextWriter outputWriter) 
        {
            EDesignUtil.CheckArgumentNull(outputWriter, "outputWriter"); 
 
            CodeDomProvider provider;
            IList schemaErrors; 
            Dictionary generatedViews;
            if (GetViewsWithErrors(mappingCollection, out provider, out schemaErrors, out generatedViews))
            {
                return schemaErrors; 
            }
 
            //Store the generated views on to the output writer passed in. 
            GenerateAndStoreViews(mappingCollection, generatedViews,
                outputWriter, provider, schemaErrors); 

            return schemaErrors;
        }
 
        /// 
        /// Validates the mappingCollections and returns the schemaErrors. 
        ///  
        /// 
        /// list of EdmSchemaError 
        public static IList Validate(StorageMappingItemCollection mappingCollection)
        {
            // purpose of this API is to validate the mappingCollection, it basically will call GetViews
 
            EntityUtil.CheckArgumentNull(mappingCollection, "mappingCollection");
 
            // we need a temp var to to pass it to GetViews (since we will directly invoke GetViews) 
            Dictionary generatedViews;
            // mappingCollection will be validated and schemaErrors will be returned from GetViews API 
            IList schemaErrors;

            GetViews(mappingCollection, out schemaErrors, out generatedViews);
 
            Debug.Assert(schemaErrors != null, "schemaErrors is null");
            return schemaErrors; 
        } 

        private bool GetViewsWithErrors(StorageMappingItemCollection mappingCollection, out CodeDomProvider provider, out IList schemaErrors, out Dictionary generatedViews) 
        {
            GetViewsAndCodeDomProvider(mappingCollection, out provider, out schemaErrors, out generatedViews);
            if (schemaErrors.Count != 0)
            { 
                //If all the schema errors are warnings, proceed without returning them right away.
                if (!MetadataHelper.CheckIfAllErrorsAreWarnings(schemaErrors)) 
                { 
                    return true;
                } 
            }
            return false;
        }
 
        private void GetViewsAndCodeDomProvider(StorageMappingItemCollection mappingCollection, out CodeDomProvider provider, out IList schemaErrors, out Dictionary generatedViews)
        { 
            EDesignUtil.CheckArgumentNull(mappingCollection, "mappingCollection"); 
            //Create a CodeDomProvider based on options.
            provider = null; 
            switch (m_languageOption)
            {
                case LanguageOption.GenerateCSharpCode:
                    provider = new Microsoft.CSharp.CSharpCodeProvider(); 
                    break;
 
                case LanguageOption.GenerateVBCode: 
                    provider = new Microsoft.VisualBasic.VBCodeProvider();
                    break; 
            }

            //Get the views for the Entity Sets and Association Sets in the mapping item collection
 

            GetViews(mappingCollection, out schemaErrors, out generatedViews); 
        } 

        private static void GetViews(StorageMappingItemCollection mappingCollection, 
            out IList schemaErrors, out Dictionary generatedViews)
        {
            //GenerateViews method requires a workspace.
            MetadataWorkspace workspace = new MetadataWorkspace(); 

            EdmItemCollection edmCollection = mappingCollection.EdmItemCollection; 
            Debug.Assert(edmCollection != null, "StorageMappingItemCollection should not allow null Edm Item Collection"); 
            workspace.RegisterItemCollection(edmCollection);
 
            StoreItemCollection storeCollection = mappingCollection.StoreItemCollection;
            Debug.Assert(storeCollection != null, "StorageMappingItemCollection should not allow null Store Item Collection");
            workspace.RegisterItemCollection(storeCollection);
            workspace.RegisterItemCollection(mappingCollection); 
            generatedViews = mappingCollection.GetViews(workspace, out schemaErrors);
        } 
 
        /// 
        /// Generates the code to store the views in a C# or a VB file based on the 
        /// options passed in by the user.
        /// 
        /// 
        ///  
        /// 
        ///  
        ///  
        private static void GenerateAndStoreViews(StorageMappingItemCollection mappingCollection,
            Dictionary generatedViews, TextWriter sourceWriter, CodeDomProvider provider, IList schemaErrors) 
        {
            EdmItemCollection edmCollection = mappingCollection.EdmItemCollection;
            StoreItemCollection storeCollection = mappingCollection.StoreItemCollection;
 
            //Create an emtpty compile unit and build up the generated code
            CodeCompileUnit compileUnit = new CodeCompileUnit(); 
 
            //Add the namespace for generated code
            CodeNamespace codeNamespace = new CodeNamespace(EntityViewGenerationConstants.NamespaceName); 
            //Add copyright notice to the namespace comment.
            compileUnit.Namespaces.Add(codeNamespace);

            foreach (var storageEntityContainerMapping in mappingCollection.GetItems()) 
            {
 
                //Throw warning when containerMapping contains query view for bug 547285. 
                if (HasQueryView(storageEntityContainerMapping))
                { 
                    schemaErrors.Add(new EdmSchemaError(
                        Strings.UnsupportedQueryViewInEntityContainerMapping(storageEntityContainerMapping.Identity),
                        (int)StorageMappingErrorCode.UnsupportedQueryViewInEntityContainerMapping,
                        EdmSchemaErrorSeverity.Warning)); 
                    continue;
                } 
 
                #region Class Declaration
 
                string edmContainerName = storageEntityContainerMapping.EdmEntityContainer.Name;
                string storeContainerName = storageEntityContainerMapping.StorageEntityContainer.Name;

                string hashOverMappingClosure = MetadataMappingHasherVisitor.GetMappingClosureHash(storageEntityContainerMapping, edmCollection); 

                StringBuilder inputForTypeNameContent = new StringBuilder(hashOverMappingClosure); 
 
                string viewStorageTypeName = EntityViewGenerationConstants.ViewGenerationTypeNamePrefix + StringHashBuilder.ComputeHash(inputForTypeNameContent.ToString()).ToUpperInvariant();
 
                //Add typeof expression to get the type that contains ViewGen type. This will help us in avoiding to go through
                //all the types in the assembly. I have also verified that this works with VB with a root namespace prepended to the
                //namespace since VB is picking up the type correctly as long as it is in the same assembly even with out the root namespace.
                CodeTypeOfExpression viewGenTypeOfExpression = new CodeTypeOfExpression(EntityViewGenerationConstants.NamespaceName + "." + viewStorageTypeName); 
                //Add the assembly attribute that marks the assembly as the one that contains the generated views
                CodeAttributeDeclaration viewGenAttribute = new CodeAttributeDeclaration(EntityViewGenerationConstants.ViewGenerationCustomAttributeName); 
                CodeAttributeArgument viewGenTypeArgument = new CodeAttributeArgument(viewGenTypeOfExpression); 
                viewGenAttribute.Arguments.Add(viewGenTypeArgument);
                compileUnit.AssemblyCustomAttributes.Add(viewGenAttribute); 

                //Add the type which will be the class that contains all the views in this assembly
                CodeTypeDeclaration viewStoringType = CreateTypeForStoringViews(viewStorageTypeName);
 
                //Add the constructor, this will be the only method that this type will contain
                //Create empty constructor. 
                CodeConstructor viewStoringTypeConstructor = CreateConstructorForViewStoringType(); 
                viewStoringType.Attributes = MemberAttributes.Public;
 

                //Get an expression that expresses this instance
                CodeThisReferenceExpression thisRef = new CodeThisReferenceExpression();
 
                //Add the views to a method
                CodeMemberMethod getViewAtMethod = new CodeMemberMethod(); 
                getViewAtMethod.Name = EntityViewGenerationConstants.GetViewAtMethodName; 
                getViewAtMethod.ReturnType = new CodeTypeReference(typeof(KeyValuePair<,>).MakeGenericType(new Type[] { typeof(string), typeof(string) }));
                CodeParameterDeclarationExpression parameter = new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(int)), "index"); 
                getViewAtMethod.Parameters.Add(parameter);
                getViewAtMethod.Comments.Add(new CodeCommentStatement(
                    Strings.GetViewAtMethodComments, false));
                getViewAtMethod.Attributes = MemberAttributes.Family | MemberAttributes.Override; 

                AddStatementsToGetAtViewMethod(getViewAtMethod, generatedViews); 
 
                string viewHash = MetadataHelper.GenerateHashForAllExtentViewsContent(GenerateDictionaryForEntitySetNameAndView(generatedViews));
 

                CodeAssignStatement EdmEntityContainerNameStatement =
                    new CodeAssignStatement(
                        new CodeFieldReferenceExpression(thisRef, EntityViewGenerationConstants.EdmEntityContainerName), 
                        new CodePrimitiveExpression(edmContainerName));
                CodeAssignStatement StoreEntityContainerNameStatement = 
                    new CodeAssignStatement( 
                        new CodeFieldReferenceExpression(thisRef, EntityViewGenerationConstants.StoreEntityContainerName),
                        new CodePrimitiveExpression(storeContainerName)); 
                CodeAssignStatement HashOverMappingClosureStatement =
                    new CodeAssignStatement(
                        new CodeFieldReferenceExpression(thisRef, EntityViewGenerationConstants.HashOverMappingClosure),
                        new CodePrimitiveExpression(hashOverMappingClosure)); 
                CodeAssignStatement HashOverAllExtentViewsStatement =
                    new CodeAssignStatement( 
                        new CodeFieldReferenceExpression(thisRef, EntityViewGenerationConstants.HashOverAllExtentViews), 
                        new CodePrimitiveExpression(viewHash));
                CodeAssignStatement ViewCountStatement = 
                    new CodeAssignStatement(
                        new CodeFieldReferenceExpression(thisRef, EntityViewGenerationConstants.ViewCountPropertyName),
                        new CodePrimitiveExpression(generatedViews.Count));
 
                viewStoringTypeConstructor.Statements.Add(EdmEntityContainerNameStatement);
                viewStoringTypeConstructor.Statements.Add(StoreEntityContainerNameStatement); 
                viewStoringTypeConstructor.Statements.Add(HashOverMappingClosureStatement); 
                viewStoringTypeConstructor.Statements.Add(HashOverAllExtentViewsStatement);
                viewStoringTypeConstructor.Statements.Add(ViewCountStatement); 

                //Add the constructor to the type
                viewStoringType.Members.Add(viewStoringTypeConstructor);
                //Add the method to store views to the type 
                viewStoringType.Members.Add(getViewAtMethod);
 
                //Add the type to the namespace 
                codeNamespace.Types.Add(viewStoringType);
 
                #endregion
            }

            if (codeNamespace.Types.Count > 0) 
            {
                GenerateCode(sourceWriter, provider, compileUnit); 
                sourceWriter.Flush(); 
            }
        } 

        private static bool HasQueryView(StorageEntityContainerMapping storageEntityContainerMapping)
        {
            foreach (EntitySetBase extent in storageEntityContainerMapping.EdmEntityContainer.BaseEntitySets) 
            {
                if (storageEntityContainerMapping.HasQueryViewForSetMap(extent.Name)) 
                { 
                    return true;
                } 
            }
            return false;
        }
 
        private static Dictionary GenerateDictionaryForEntitySetNameAndView(Dictionary dictionary)
        { 
            Dictionary newDictionary = new Dictionary(); 
            foreach (var item in dictionary)
            { 
                newDictionary.Add(GetExtentFullName(item.Key), item.Value);
            }
            return newDictionary;
        } 

        ///  
        /// Write code to the given stream from the compile unit. 
        /// 
        ///  
        /// 
        /// 
        private static void GenerateCode(TextWriter sourceWriter, CodeDomProvider provider, CodeCompileUnit compileUnit)
        { 
            CodeGeneratorOptions styleOptions = new CodeGeneratorOptions();
            styleOptions.BracingStyle = "C"; 
            styleOptions.BlankLinesBetweenMembers = true; 
            styleOptions.VerbatimOrder = true;
            provider.GenerateCodeFromCompileUnit(compileUnit, sourceWriter, styleOptions); 
        }

        /// 
        /// Generate Code to put the views in the generated code. 
        /// 
        ///  
        ///  
        /// 
        ///  
        private static void AddStatementsToGetAtViewMethod(CodeMemberMethod getAtViewMethod,
            Dictionary generatedViews)
        {
            int index = 0; 
            CodeConditionStatement lastIf = null;
            CodeVariableReferenceExpression indexParameterReference = new CodeVariableReferenceExpression(getAtViewMethod.Parameters[0].Name); 
            foreach (KeyValuePair generatedViewPair in generatedViews) 
            {
                CodeConditionStatement currentIf = new CodeConditionStatement(new CodeBinaryOperatorExpression( 
                    indexParameterReference, CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(index)));

                if (lastIf == null)
                { 
                    // this is the first one add it to the method
                    getAtViewMethod.Statements.Add(currentIf); 
                } 
                else
                { 
                    // this is the nth one add it to the false part of the last
                    // if
                    lastIf.FalseStatements.Add(currentIf);
                } 
                lastIf = currentIf;
 
                EntitySetBase entitySet = generatedViewPair.Key; 
                string extentFullName = GetExtentFullName(entitySet);
 
                //Add a comment stating the name of the extent for which the view is being added
                currentIf.TrueStatements.Add(new CodeCommentStatement(Strings.IndividualViewComments(extentFullName),false));
                CodeObjectCreateExpression newExpression = new CodeObjectCreateExpression(getAtViewMethod.ReturnType, new CodePrimitiveExpression(extentFullName), new CodePrimitiveExpression(generatedViewPair.Value));
                currentIf.TrueStatements.Add(new CodeMethodReturnStatement(newExpression)); 
                index++;
            } 
 
            // if an invalid index is asked for throw
            getAtViewMethod.Statements.Add(new CodeThrowExceptionStatement( 
                                            new CodeObjectCreateExpression(new CodeTypeReference(typeof(IndexOutOfRangeException)))));
        }

        private static string GetExtentFullName(EntitySetBase entitySet) 
        {
            //We store the full Extent Name in the generated code which is 
            //EntityContainer name + "." + entitysetName 
            return entitySet.EntityContainer.Name + EntityViewGenerationConstants.QualificationCharacter + entitySet.Name;
 
        }

        /// 
        /// Get the constructor for the type that will contain the generated views 
        /// 
        ///  
        private static CodeConstructor CreateConstructorForViewStoringType() 
        {
            CodeConstructor constructor = new CodeConstructor(); 
            //Mark it as public
            constructor.Attributes = MemberAttributes.Public;
            //Add constructor comments
            constructor.Comments.Add(new CodeCommentStatement(EntityViewGenerationConstants.SummaryStartElement, true /*docComment*/)); 
            constructor.Comments.Add(new CodeCommentStatement(Strings.ConstructorComments, true /*docComment*/));
            constructor.Comments.Add(new CodeCommentStatement(EntityViewGenerationConstants.SummaryEndElement, true /*docComment*/)); 
            return constructor; 
        }
 
        /// 
        /// Get the type declaration for the type that will contain the views.
        /// 
        ///  
        private static CodeTypeDeclaration CreateTypeForStoringViews(string viewStorageTypeName)
        { 
            CodeTypeDeclaration typeDecl = new CodeTypeDeclaration(viewStorageTypeName); 
            typeDecl.TypeAttributes = TypeAttributes.Sealed | TypeAttributes.Public;
            //This type should derive from the framework type EntityViewContainer which reduces the amount 
            //of generated code
            typeDecl.BaseTypes.Add(EntityViewGenerationConstants.BaseTypeName);
            //Add type comments
            typeDecl.Comments.Add(new CodeCommentStatement(EntityViewGenerationConstants.SummaryStartElement, true /*docComment*/)); 
            typeDecl.Comments.Add(new CodeCommentStatement(Strings.TypeComments, true /*docComment*/));
            typeDecl.Comments.Add(new CodeCommentStatement(EntityViewGenerationConstants.SummaryEndElement, true /*docComment*/)); 
            return typeDecl; 
        }
        #endregion 
    }
}

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

using System; 
using System.CodeDom;
using System.CodeDom.Compiler;
using System.IO;
using System.Collections.Generic; 
using System.Text;
using System.Data; 
using System.Data.SqlClient; 
using System.Data.Metadata.Edm;
using System.Data.Mapping; 
using System.Data.EntityClient;
using System.Data.EntityModel;
using System.Data.Common.CommandTrees;
using System.Reflection; 
using System.Security.Cryptography;
using System.Data.Entity.Design.Common; 
using System.Diagnostics; 
using System.Globalization;
using System.Data.Common.Utils; 

namespace System.Data.Entity.Design
{
    ///  
    /// EntityViewGenerator class produces the views for the extents in the passed in StorageMappingItemCollection.
    /// The views are written as code to the passed in output stream. There are a set of options that user 
    /// can use to control the code generation process. The options should be apssed into the constrcutor. 
    /// While storing the views in the code, the view generator class also stores a Hash value produced based
    /// on the content of the views and the names of extents. We also generate a hash for each schema file( csdl, ssdl and msl) 
    /// that was used in view generation process and store the hash in the generated code.The entity runtime will try to discover this
    /// type and if it does discover it will use the generated views in this type. The discovery process is
    /// explained in detail in the comments for StorageMappingItemCollection class.
    /// The runtime will throw an exception if any of the the hash values produced in the design time does not match 
    /// the hash values produced at the runtime.
    ///  
    public class EntityViewGenerator 
    {
        #region Constructors 
        /// 
        /// Create the instance of ViewGenerator with the given language option.
        /// 
        /// Language Option for generated code. 
        public EntityViewGenerator(LanguageOption languageOption)
        { 
            m_languageOption = EDesignUtil.CheckLanguageOptionArgument(languageOption, "languageOption"); 
        }
 
        /// 
        /// Create the instance of ViewGenerator using C# as the default
        /// language option.
        ///  
        public EntityViewGenerator()
            : this(LanguageOption.GenerateCSharpCode) 
        { 
        }
 
        #endregion

        #region Fields
        private LanguageOption m_languageOption; 
        #endregion
 
        #region Properties 
        /// 
        /// Language Option for generated code. 
        /// 
        public LanguageOption LanguageOption
        {
            get { return m_languageOption; } 
            set { m_languageOption = EDesignUtil.CheckLanguageOptionArgument(value, "value"); }
        } 
        #endregion 

        #region Methods 
        /// 
        /// Generates the views for the extents in the mapping item collection and produces
        /// the code for a type that will cache these views. The methods also produces
        /// a hash based on the StorageEntityContainerMapping, which contains all the 
        /// metadata and mapping. It also produces a hash based
        /// on the view content and the name of the extents. 
        ///  
        /// Mapping Item Collection for which views should be generated
        /// Uri to which generated code needs to be written 
        public IList GenerateViews(StorageMappingItemCollection mappingCollection, string outputPath)
        {
            EDesignUtil.CheckStringArgument(outputPath, "outputPath");
 
            CodeDomProvider provider;
            IList schemaErrors; 
            Dictionary generatedViews; 
            if (GetViewsWithErrors(mappingCollection, out provider, out schemaErrors, out generatedViews))
            { 
                return schemaErrors;
            }

            //Create a stream over the output URI to write the generated code 
            using (StreamWriter outputWriter = new System.IO.StreamWriter(outputPath))
            { 
                GenerateAndStoreViews(mappingCollection, generatedViews, 
                    outputWriter, provider, schemaErrors);
            } 
            return schemaErrors;
        }

        ///  
        /// Generates the views for the extents in the mapping item collection and produces
        /// the code for a type that will cache these views. The methods also produces 
        /// a hash based on the storageEntityContainerMapping object, which contains all the 
        /// metadata and mapping. It also produces a hash based
        /// on the view content and the name of the extents. 
        /// 
        /// Mapping Item Collection for which views should be generated
        /// Output writer to which we want to write the code
        public IList GenerateViews(StorageMappingItemCollection mappingCollection, TextWriter outputWriter) 
        {
            EDesignUtil.CheckArgumentNull(outputWriter, "outputWriter"); 
 
            CodeDomProvider provider;
            IList schemaErrors; 
            Dictionary generatedViews;
            if (GetViewsWithErrors(mappingCollection, out provider, out schemaErrors, out generatedViews))
            {
                return schemaErrors; 
            }
 
            //Store the generated views on to the output writer passed in. 
            GenerateAndStoreViews(mappingCollection, generatedViews,
                outputWriter, provider, schemaErrors); 

            return schemaErrors;
        }
 
        /// 
        /// Validates the mappingCollections and returns the schemaErrors. 
        ///  
        /// 
        /// list of EdmSchemaError 
        public static IList Validate(StorageMappingItemCollection mappingCollection)
        {
            // purpose of this API is to validate the mappingCollection, it basically will call GetViews
 
            EntityUtil.CheckArgumentNull(mappingCollection, "mappingCollection");
 
            // we need a temp var to to pass it to GetViews (since we will directly invoke GetViews) 
            Dictionary generatedViews;
            // mappingCollection will be validated and schemaErrors will be returned from GetViews API 
            IList schemaErrors;

            GetViews(mappingCollection, out schemaErrors, out generatedViews);
 
            Debug.Assert(schemaErrors != null, "schemaErrors is null");
            return schemaErrors; 
        } 

        private bool GetViewsWithErrors(StorageMappingItemCollection mappingCollection, out CodeDomProvider provider, out IList schemaErrors, out Dictionary generatedViews) 
        {
            GetViewsAndCodeDomProvider(mappingCollection, out provider, out schemaErrors, out generatedViews);
            if (schemaErrors.Count != 0)
            { 
                //If all the schema errors are warnings, proceed without returning them right away.
                if (!MetadataHelper.CheckIfAllErrorsAreWarnings(schemaErrors)) 
                { 
                    return true;
                } 
            }
            return false;
        }
 
        private void GetViewsAndCodeDomProvider(StorageMappingItemCollection mappingCollection, out CodeDomProvider provider, out IList schemaErrors, out Dictionary generatedViews)
        { 
            EDesignUtil.CheckArgumentNull(mappingCollection, "mappingCollection"); 
            //Create a CodeDomProvider based on options.
            provider = null; 
            switch (m_languageOption)
            {
                case LanguageOption.GenerateCSharpCode:
                    provider = new Microsoft.CSharp.CSharpCodeProvider(); 
                    break;
 
                case LanguageOption.GenerateVBCode: 
                    provider = new Microsoft.VisualBasic.VBCodeProvider();
                    break; 
            }

            //Get the views for the Entity Sets and Association Sets in the mapping item collection
 

            GetViews(mappingCollection, out schemaErrors, out generatedViews); 
        } 

        private static void GetViews(StorageMappingItemCollection mappingCollection, 
            out IList schemaErrors, out Dictionary generatedViews)
        {
            //GenerateViews method requires a workspace.
            MetadataWorkspace workspace = new MetadataWorkspace(); 

            EdmItemCollection edmCollection = mappingCollection.EdmItemCollection; 
            Debug.Assert(edmCollection != null, "StorageMappingItemCollection should not allow null Edm Item Collection"); 
            workspace.RegisterItemCollection(edmCollection);
 
            StoreItemCollection storeCollection = mappingCollection.StoreItemCollection;
            Debug.Assert(storeCollection != null, "StorageMappingItemCollection should not allow null Store Item Collection");
            workspace.RegisterItemCollection(storeCollection);
            workspace.RegisterItemCollection(mappingCollection); 
            generatedViews = mappingCollection.GetViews(workspace, out schemaErrors);
        } 
 
        /// 
        /// Generates the code to store the views in a C# or a VB file based on the 
        /// options passed in by the user.
        /// 
        /// 
        ///  
        /// 
        ///  
        ///  
        private static void GenerateAndStoreViews(StorageMappingItemCollection mappingCollection,
            Dictionary generatedViews, TextWriter sourceWriter, CodeDomProvider provider, IList schemaErrors) 
        {
            EdmItemCollection edmCollection = mappingCollection.EdmItemCollection;
            StoreItemCollection storeCollection = mappingCollection.StoreItemCollection;
 
            //Create an emtpty compile unit and build up the generated code
            CodeCompileUnit compileUnit = new CodeCompileUnit(); 
 
            //Add the namespace for generated code
            CodeNamespace codeNamespace = new CodeNamespace(EntityViewGenerationConstants.NamespaceName); 
            //Add copyright notice to the namespace comment.
            compileUnit.Namespaces.Add(codeNamespace);

            foreach (var storageEntityContainerMapping in mappingCollection.GetItems()) 
            {
 
                //Throw warning when containerMapping contains query view for bug 547285. 
                if (HasQueryView(storageEntityContainerMapping))
                { 
                    schemaErrors.Add(new EdmSchemaError(
                        Strings.UnsupportedQueryViewInEntityContainerMapping(storageEntityContainerMapping.Identity),
                        (int)StorageMappingErrorCode.UnsupportedQueryViewInEntityContainerMapping,
                        EdmSchemaErrorSeverity.Warning)); 
                    continue;
                } 
 
                #region Class Declaration
 
                string edmContainerName = storageEntityContainerMapping.EdmEntityContainer.Name;
                string storeContainerName = storageEntityContainerMapping.StorageEntityContainer.Name;

                string hashOverMappingClosure = MetadataMappingHasherVisitor.GetMappingClosureHash(storageEntityContainerMapping, edmCollection); 

                StringBuilder inputForTypeNameContent = new StringBuilder(hashOverMappingClosure); 
 
                string viewStorageTypeName = EntityViewGenerationConstants.ViewGenerationTypeNamePrefix + StringHashBuilder.ComputeHash(inputForTypeNameContent.ToString()).ToUpperInvariant();
 
                //Add typeof expression to get the type that contains ViewGen type. This will help us in avoiding to go through
                //all the types in the assembly. I have also verified that this works with VB with a root namespace prepended to the
                //namespace since VB is picking up the type correctly as long as it is in the same assembly even with out the root namespace.
                CodeTypeOfExpression viewGenTypeOfExpression = new CodeTypeOfExpression(EntityViewGenerationConstants.NamespaceName + "." + viewStorageTypeName); 
                //Add the assembly attribute that marks the assembly as the one that contains the generated views
                CodeAttributeDeclaration viewGenAttribute = new CodeAttributeDeclaration(EntityViewGenerationConstants.ViewGenerationCustomAttributeName); 
                CodeAttributeArgument viewGenTypeArgument = new CodeAttributeArgument(viewGenTypeOfExpression); 
                viewGenAttribute.Arguments.Add(viewGenTypeArgument);
                compileUnit.AssemblyCustomAttributes.Add(viewGenAttribute); 

                //Add the type which will be the class that contains all the views in this assembly
                CodeTypeDeclaration viewStoringType = CreateTypeForStoringViews(viewStorageTypeName);
 
                //Add the constructor, this will be the only method that this type will contain
                //Create empty constructor. 
                CodeConstructor viewStoringTypeConstructor = CreateConstructorForViewStoringType(); 
                viewStoringType.Attributes = MemberAttributes.Public;
 

                //Get an expression that expresses this instance
                CodeThisReferenceExpression thisRef = new CodeThisReferenceExpression();
 
                //Add the views to a method
                CodeMemberMethod getViewAtMethod = new CodeMemberMethod(); 
                getViewAtMethod.Name = EntityViewGenerationConstants.GetViewAtMethodName; 
                getViewAtMethod.ReturnType = new CodeTypeReference(typeof(KeyValuePair<,>).MakeGenericType(new Type[] { typeof(string), typeof(string) }));
                CodeParameterDeclarationExpression parameter = new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(int)), "index"); 
                getViewAtMethod.Parameters.Add(parameter);
                getViewAtMethod.Comments.Add(new CodeCommentStatement(
                    Strings.GetViewAtMethodComments, false));
                getViewAtMethod.Attributes = MemberAttributes.Family | MemberAttributes.Override; 

                AddStatementsToGetAtViewMethod(getViewAtMethod, generatedViews); 
 
                string viewHash = MetadataHelper.GenerateHashForAllExtentViewsContent(GenerateDictionaryForEntitySetNameAndView(generatedViews));
 

                CodeAssignStatement EdmEntityContainerNameStatement =
                    new CodeAssignStatement(
                        new CodeFieldReferenceExpression(thisRef, EntityViewGenerationConstants.EdmEntityContainerName), 
                        new CodePrimitiveExpression(edmContainerName));
                CodeAssignStatement StoreEntityContainerNameStatement = 
                    new CodeAssignStatement( 
                        new CodeFieldReferenceExpression(thisRef, EntityViewGenerationConstants.StoreEntityContainerName),
                        new CodePrimitiveExpression(storeContainerName)); 
                CodeAssignStatement HashOverMappingClosureStatement =
                    new CodeAssignStatement(
                        new CodeFieldReferenceExpression(thisRef, EntityViewGenerationConstants.HashOverMappingClosure),
                        new CodePrimitiveExpression(hashOverMappingClosure)); 
                CodeAssignStatement HashOverAllExtentViewsStatement =
                    new CodeAssignStatement( 
                        new CodeFieldReferenceExpression(thisRef, EntityViewGenerationConstants.HashOverAllExtentViews), 
                        new CodePrimitiveExpression(viewHash));
                CodeAssignStatement ViewCountStatement = 
                    new CodeAssignStatement(
                        new CodeFieldReferenceExpression(thisRef, EntityViewGenerationConstants.ViewCountPropertyName),
                        new CodePrimitiveExpression(generatedViews.Count));
 
                viewStoringTypeConstructor.Statements.Add(EdmEntityContainerNameStatement);
                viewStoringTypeConstructor.Statements.Add(StoreEntityContainerNameStatement); 
                viewStoringTypeConstructor.Statements.Add(HashOverMappingClosureStatement); 
                viewStoringTypeConstructor.Statements.Add(HashOverAllExtentViewsStatement);
                viewStoringTypeConstructor.Statements.Add(ViewCountStatement); 

                //Add the constructor to the type
                viewStoringType.Members.Add(viewStoringTypeConstructor);
                //Add the method to store views to the type 
                viewStoringType.Members.Add(getViewAtMethod);
 
                //Add the type to the namespace 
                codeNamespace.Types.Add(viewStoringType);
 
                #endregion
            }

            if (codeNamespace.Types.Count > 0) 
            {
                GenerateCode(sourceWriter, provider, compileUnit); 
                sourceWriter.Flush(); 
            }
        } 

        private static bool HasQueryView(StorageEntityContainerMapping storageEntityContainerMapping)
        {
            foreach (EntitySetBase extent in storageEntityContainerMapping.EdmEntityContainer.BaseEntitySets) 
            {
                if (storageEntityContainerMapping.HasQueryViewForSetMap(extent.Name)) 
                { 
                    return true;
                } 
            }
            return false;
        }
 
        private static Dictionary GenerateDictionaryForEntitySetNameAndView(Dictionary dictionary)
        { 
            Dictionary newDictionary = new Dictionary(); 
            foreach (var item in dictionary)
            { 
                newDictionary.Add(GetExtentFullName(item.Key), item.Value);
            }
            return newDictionary;
        } 

        ///  
        /// Write code to the given stream from the compile unit. 
        /// 
        ///  
        /// 
        /// 
        private static void GenerateCode(TextWriter sourceWriter, CodeDomProvider provider, CodeCompileUnit compileUnit)
        { 
            CodeGeneratorOptions styleOptions = new CodeGeneratorOptions();
            styleOptions.BracingStyle = "C"; 
            styleOptions.BlankLinesBetweenMembers = true; 
            styleOptions.VerbatimOrder = true;
            provider.GenerateCodeFromCompileUnit(compileUnit, sourceWriter, styleOptions); 
        }

        /// 
        /// Generate Code to put the views in the generated code. 
        /// 
        ///  
        ///  
        /// 
        ///  
        private static void AddStatementsToGetAtViewMethod(CodeMemberMethod getAtViewMethod,
            Dictionary generatedViews)
        {
            int index = 0; 
            CodeConditionStatement lastIf = null;
            CodeVariableReferenceExpression indexParameterReference = new CodeVariableReferenceExpression(getAtViewMethod.Parameters[0].Name); 
            foreach (KeyValuePair generatedViewPair in generatedViews) 
            {
                CodeConditionStatement currentIf = new CodeConditionStatement(new CodeBinaryOperatorExpression( 
                    indexParameterReference, CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(index)));

                if (lastIf == null)
                { 
                    // this is the first one add it to the method
                    getAtViewMethod.Statements.Add(currentIf); 
                } 
                else
                { 
                    // this is the nth one add it to the false part of the last
                    // if
                    lastIf.FalseStatements.Add(currentIf);
                } 
                lastIf = currentIf;
 
                EntitySetBase entitySet = generatedViewPair.Key; 
                string extentFullName = GetExtentFullName(entitySet);
 
                //Add a comment stating the name of the extent for which the view is being added
                currentIf.TrueStatements.Add(new CodeCommentStatement(Strings.IndividualViewComments(extentFullName),false));
                CodeObjectCreateExpression newExpression = new CodeObjectCreateExpression(getAtViewMethod.ReturnType, new CodePrimitiveExpression(extentFullName), new CodePrimitiveExpression(generatedViewPair.Value));
                currentIf.TrueStatements.Add(new CodeMethodReturnStatement(newExpression)); 
                index++;
            } 
 
            // if an invalid index is asked for throw
            getAtViewMethod.Statements.Add(new CodeThrowExceptionStatement( 
                                            new CodeObjectCreateExpression(new CodeTypeReference(typeof(IndexOutOfRangeException)))));
        }

        private static string GetExtentFullName(EntitySetBase entitySet) 
        {
            //We store the full Extent Name in the generated code which is 
            //EntityContainer name + "." + entitysetName 
            return entitySet.EntityContainer.Name + EntityViewGenerationConstants.QualificationCharacter + entitySet.Name;
 
        }

        /// 
        /// Get the constructor for the type that will contain the generated views 
        /// 
        ///  
        private static CodeConstructor CreateConstructorForViewStoringType() 
        {
            CodeConstructor constructor = new CodeConstructor(); 
            //Mark it as public
            constructor.Attributes = MemberAttributes.Public;
            //Add constructor comments
            constructor.Comments.Add(new CodeCommentStatement(EntityViewGenerationConstants.SummaryStartElement, true /*docComment*/)); 
            constructor.Comments.Add(new CodeCommentStatement(Strings.ConstructorComments, true /*docComment*/));
            constructor.Comments.Add(new CodeCommentStatement(EntityViewGenerationConstants.SummaryEndElement, true /*docComment*/)); 
            return constructor; 
        }
 
        /// 
        /// Get the type declaration for the type that will contain the views.
        /// 
        ///  
        private static CodeTypeDeclaration CreateTypeForStoringViews(string viewStorageTypeName)
        { 
            CodeTypeDeclaration typeDecl = new CodeTypeDeclaration(viewStorageTypeName); 
            typeDecl.TypeAttributes = TypeAttributes.Sealed | TypeAttributes.Public;
            //This type should derive from the framework type EntityViewContainer which reduces the amount 
            //of generated code
            typeDecl.BaseTypes.Add(EntityViewGenerationConstants.BaseTypeName);
            //Add type comments
            typeDecl.Comments.Add(new CodeCommentStatement(EntityViewGenerationConstants.SummaryStartElement, true /*docComment*/)); 
            typeDecl.Comments.Add(new CodeCommentStatement(Strings.TypeComments, true /*docComment*/));
            typeDecl.Comments.Add(new CodeCommentStatement(EntityViewGenerationConstants.SummaryEndElement, true /*docComment*/)); 
            return typeDecl; 
        }
        #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