1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
|
//---------------------------------------------------------------------
// <copyright file="NamespaceEmitter.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System;
using System.CodeDom;
using System.Data;
using Som = System.Data.EntityModel.SchemaObjectModel;
using System.Collections.Generic;
using System.Data.Entity.Design;
using System.Data.Metadata.Edm;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Data.Entity.Design.SsdlGenerator;
using System.Data.Entity.Design.Common;
namespace System.Data.EntityModel.Emitters
{
/// <summary>
/// This class is responsible for Emitting the code to create the CLR namespace container and assembly level attributes
/// </summary>
internal sealed class NamespaceEmitter : Emitter
{
#region Static Fields
private static Pair<Type, CreateEmitter>[] EmitterCreators = new Pair<Type, CreateEmitter>[]
{
new Pair<Type,CreateEmitter>(typeof(EntityType), delegate (ClientApiGenerator generator, GlobalItem element) { return new EntityTypeEmitter(generator,(EntityType)element); }),
new Pair<Type,CreateEmitter>(typeof(ComplexType), delegate (ClientApiGenerator generator, GlobalItem element) { return new ComplexTypeEmitter(generator,(ComplexType)element); }),
new Pair<Type,CreateEmitter>(typeof(EntityContainer), delegate (ClientApiGenerator generator, GlobalItem element) { return new EntityContainerEmitter(generator,(EntityContainer)element); }),
new Pair<Type,CreateEmitter>(typeof(AssociationType), delegate (ClientApiGenerator generator, GlobalItem element) { return new AssociationTypeEmitter(generator,(AssociationType)element); }),
};
#endregion
#region Private Fields
private string _codeNamespace = null;
private string _targetFilePath = null;
#endregion
#region Public Methods
/// <summary>
///
/// </summary>
/// <param name="generator"></param>
public NamespaceEmitter(ClientApiGenerator generator, string codeNamespace, string targetFilePath)
: base(generator)
{
_codeNamespace = codeNamespace;
_targetFilePath = targetFilePath != null ? targetFilePath : string.Empty;
}
/// <summary>
/// Creates the CodeTypeDeclarations necessary to generate the code
/// </summary>
public void Emit()
{
// it is a valid scenario for namespaceName to be empty
string namespaceName = Generator.SourceObjectNamespaceName;
// emit the namespace definition
CodeNamespace codeNamespace = new CodeNamespace( namespaceName );
// output some boiler plate comments
string comments = Strings.NamespaceComments(
System.IO.Path.GetFileName( _targetFilePath ),
DateTime.Now.ToString( System.Globalization.CultureInfo.CurrentCulture ));
CommentEmitter.EmitComments( CommentEmitter.GetFormattedLines( comments, false ), codeNamespace.Comments, false );
CompileUnit.Namespaces.Add( codeNamespace );
// Add the assembly attribute.
CodeAttributeDeclaration assemblyAttribute;
// SQLBUDT 505339: VB compiler fails if multiple assembly attributes exist in the same project.
// This adds a GUID to the assembly attribute so that each generated file will have a unique EdmSchemaAttribute in VB.
if (this.Generator.Language == System.Data.Entity.Design.LanguageOption.GenerateVBCode) //The GUID is only added in VB
{
assemblyAttribute = AttributeEmitter.EmitSimpleAttribute("System.Data.Objects.DataClasses.EdmSchemaAttribute", System.Guid.NewGuid().ToString());
}
else
{
assemblyAttribute = AttributeEmitter.EmitSimpleAttribute("System.Data.Objects.DataClasses.EdmSchemaAttribute");
}
CompileUnit.AssemblyCustomAttributes.Add(assemblyAttribute);
Dictionary<string, string> usedClassName = new Dictionary<string, string>(StringComparer.Ordinal);
// Emit the classes in the schema
foreach (GlobalItem element in Generator.GetSourceTypes())
{
Debug.Assert(!(element is EdmFunction), "Are you trying to emit functions now? If so add an emitter for it.");
if (AddElementNameToCache(element, usedClassName))
{
SchemaTypeEmitter emitter = CreateElementEmitter(element);
CodeTypeDeclarationCollection typeDeclaration = emitter.EmitApiClass();
if (typeDeclaration.Count > 0)
{
codeNamespace.Types.AddRange(typeDeclaration);
}
}
}
}
#endregion
#region Private Properties
/// <summary>
/// Gets the compile unit (top level codedom object)
/// </summary>
/// <value></value>
private CodeCompileUnit CompileUnit
{
get
{
return Generator.CompileUnit;
}
}
#endregion
private bool AddElementNameToCache(GlobalItem element, Dictionary<string, string> cache)
{
if (element.BuiltInTypeKind == BuiltInTypeKind.EntityContainer)
{
return TryAddNameToCache((element as EntityContainer).Name, element.BuiltInTypeKind.ToString(), cache);
}
else if (element.BuiltInTypeKind == BuiltInTypeKind.EntityType ||
element.BuiltInTypeKind == BuiltInTypeKind.ComplexType ||
element.BuiltInTypeKind == BuiltInTypeKind.AssociationType)
{
return TryAddNameToCache((element as StructuralType).Name, element.BuiltInTypeKind.ToString(), cache);
}
return true;
}
private bool TryAddNameToCache(string name, string type, Dictionary<string, string> cache)
{
if (!cache.ContainsKey(name))
{
cache.Add(name, type);
}
else
{
this.Generator.AddError(Strings.DuplicateClassName(type, name, cache[name]), ModelBuilderErrorCode.DuplicateClassName,
EdmSchemaErrorSeverity.Error, name);
return false;
}
return true;
}
/// <summary>
/// Create an Emitter for a schema type element
/// </summary>
/// <param name="element"></param>
/// <returns></returns>
private SchemaTypeEmitter CreateElementEmitter( GlobalItem element )
{
Type typeOfElement = element.GetType();
foreach ( Pair<Type, CreateEmitter> pair in EmitterCreators )
{
if ( pair.First.IsAssignableFrom( typeOfElement ) )
return pair.Second( Generator, element );
}
return null;
}
private delegate SchemaTypeEmitter CreateEmitter( ClientApiGenerator generator, GlobalItem item );
/// <summary>
/// Reponsible for relating two objects together into a pair
/// </summary>
/// <typeparam name="T1"></typeparam>
/// <typeparam name="T2"></typeparam>
private class Pair<T1, T2>
{
public T1 First;
public T2 Second;
internal Pair( T1 first, T2 second )
{
First = first;
Second = second;
}
}
}
}
|