Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / ndp / fx / src / DataEntityDesign / Design / System / Data / Entity / Design / EntityViewGeneration / EntityViewGenerator.cs / 5 / 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

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- PrintController.cs
- AccessorTable.cs
- TypeDelegator.cs
- CompoundFileDeflateTransform.cs
- HitTestResult.cs
- AuthorizationRuleCollection.cs
- DataServiceQueryProvider.cs
- safex509handles.cs
- FragmentQueryProcessor.cs
- FindCompletedEventArgs.cs
- DriveNotFoundException.cs
- ManagementObjectCollection.cs
- AsnEncodedData.cs
- KeyValuePairs.cs
- Label.cs
- DataSourceXmlSerializer.cs
- StorageBasedPackageProperties.cs
- IListConverters.cs
- ReflectEventDescriptor.cs
- FloaterBaseParagraph.cs
- WebPartMinimizeVerb.cs
- ProfileService.cs
- Attributes.cs
- ClientBuildManagerCallback.cs
- DataSourceDesigner.cs
- DiscriminatorMap.cs
- EncryptedKeyIdentifierClause.cs
- DurableInstancingOptions.cs
- XmlRootAttribute.cs
- SqlDataSourceConnectionPanel.cs
- DocumentGridContextMenu.cs
- ProcessInfo.cs
- TypeForwardedToAttribute.cs
- AssemblyHash.cs
- TextProperties.cs
- ObjectHandle.cs
- RangeContentEnumerator.cs
- SerialReceived.cs
- BinaryFormatter.cs
- controlskin.cs
- DataBoundControl.cs
- SharedStream.cs
- SignatureToken.cs
- FragmentQuery.cs
- IconHelper.cs
- ProfileSettings.cs
- WindowsTab.cs
- TextDecorationUnitValidation.cs
- EventToken.cs
- ExtendedProtectionPolicyElement.cs
- WebPartMenuStyle.cs
- InfiniteTimeSpanConverter.cs
- DataFormat.cs
- DbQueryCommandTree.cs
- StorageEntityContainerMapping.cs
- XmlAggregates.cs
- keycontainerpermission.cs
- AuthStoreRoleProvider.cs
- AuthorizationRule.cs
- Win32.cs
- DataGridColumnCollectionEditor.cs
- X500Name.cs
- CreateUserErrorEventArgs.cs
- RuntimeResourceSet.cs
- ToggleButtonAutomationPeer.cs
- TemplateManager.cs
- FixedSOMPage.cs
- COM2PropertyPageUITypeConverter.cs
- ClassGenerator.cs
- TabPanel.cs
- DependencyProperty.cs
- ErrorView.xaml.cs
- CursorInteropHelper.cs
- InvokeCompletedEventArgs.cs
- TransactedReceiveScope.cs
- AggregationMinMaxHelpers.cs
- TypeUtil.cs
- LocationChangedEventArgs.cs
- SignedXml.cs
- DataGridColumnCollection.cs
- DataGridParentRows.cs
- SmtpCommands.cs
- UseLicense.cs
- LineBreak.cs
- StrongNameHelpers.cs
- ClosableStream.cs
- PassportPrincipal.cs
- StringSource.cs
- Style.cs
- ConnectionStringsExpressionBuilder.cs
- CatalogPartChrome.cs
- BatchWriter.cs
- InternalsVisibleToAttribute.cs
- EventBuilder.cs
- DataTableNewRowEvent.cs
- TrackBarRenderer.cs
- NativeMethods.cs
- ObjectSet.cs
- OracleParameter.cs
- ConstrainedDataObject.cs