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 IListGenerateViews(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 IListGenerateViews(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 IListValidate(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 IListGenerateViews(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 IListGenerateViews(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 IListValidate(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
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- COM2ColorConverter.cs
- FileUpload.cs
- NotCondition.cs
- ExpandSegmentCollection.cs
- OleDbConnectionPoolGroupProviderInfo.cs
- CultureMapper.cs
- QuadTree.cs
- Bitmap.cs
- DefaultValueTypeConverter.cs
- QilTargetType.cs
- FormViewInsertedEventArgs.cs
- StaticResourceExtension.cs
- SaveRecipientRequest.cs
- LocalTransaction.cs
- ImageListStreamer.cs
- ObjectDataSourceMethodEventArgs.cs
- SelectionChangedEventArgs.cs
- XmlNodeChangedEventManager.cs
- IOException.cs
- FloaterParaClient.cs
- TableLayoutPanelCellPosition.cs
- Positioning.cs
- RewritingValidator.cs
- ChangeNode.cs
- Assembly.cs
- ButtonBase.cs
- SqlClientWrapperSmiStreamChars.cs
- SHA1Managed.cs
- PageParser.cs
- AssociationTypeEmitter.cs
- GenericEnumerator.cs
- CorePropertiesFilter.cs
- FieldAccessException.cs
- InstanceOwnerException.cs
- CryptoStream.cs
- TreeViewBindingsEditor.cs
- ApplicationFileCodeDomTreeGenerator.cs
- MobileControlsSectionHandler.cs
- FactoryId.cs
- Form.cs
- DataBoundControlAdapter.cs
- RegexCaptureCollection.cs
- UnaryNode.cs
- MouseOverProperty.cs
- RelationshipConstraintValidator.cs
- Helper.cs
- ClientTargetCollection.cs
- BamlMapTable.cs
- IISUnsafeMethods.cs
- OperatingSystemVersionCheck.cs
- ErrorFormatterPage.cs
- XmlName.cs
- DesignTimeResourceProviderFactoryAttribute.cs
- XmlQueryType.cs
- AsymmetricKeyExchangeFormatter.cs
- CommandConverter.cs
- XmlSchemaSubstitutionGroup.cs
- DBCommand.cs
- Polygon.cs
- SqlTypeSystemProvider.cs
- AuthenticationService.cs
- ToolStripContentPanelRenderEventArgs.cs
- KeyValueInternalCollection.cs
- NamespaceDecl.cs
- ExtractCollection.cs
- Automation.cs
- ListMarkerSourceInfo.cs
- CurrencyManager.cs
- StringResourceManager.cs
- RotateTransform3D.cs
- InheritablePropertyChangeInfo.cs
- Debug.cs
- BamlLocalizer.cs
- TextRunCacheImp.cs
- ObjRef.cs
- Knowncolors.cs
- AnalyzedTree.cs
- PeerDefaultCustomResolverClient.cs
- SchemaAttDef.cs
- _HeaderInfoTable.cs
- ScopelessEnumAttribute.cs
- ConstNode.cs
- RoleManagerModule.cs
- EntityDataSourceSelectingEventArgs.cs
- GuidTagList.cs
- sortedlist.cs
- DockPatternIdentifiers.cs
- AsymmetricSignatureFormatter.cs
- SqlProviderServices.cs
- RuleValidation.cs
- SyndicationDeserializer.cs
- mda.cs
- CounterCreationDataConverter.cs
- OutputCacheSettings.cs
- EllipseGeometry.cs
- ScriptReferenceBase.cs
- PlainXmlSerializer.cs
- ToolStripContentPanel.cs
- FastEncoder.cs
- DesignerLoader.cs