You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
@@ -0,0 +1,93 @@
|
||||
//---------------------------------------------------------------------
|
||||
// <copyright file="EdmToObjectNamespaceMap.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//
|
||||
// @owner [....]
|
||||
// @backupOwner [....]
|
||||
//---------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Data.Entity.Design.Common;
|
||||
|
||||
namespace System.Data.Entity.Design
|
||||
{
|
||||
/// <summary>
|
||||
/// The class to hold the map entries for the mapping between Edm Namespace and the Object Namespace
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Edm")]
|
||||
public class EdmToObjectNamespaceMap
|
||||
{
|
||||
private Dictionary<string, string> _map = new Dictionary<string, string>();
|
||||
|
||||
/// <summary>
|
||||
/// this is just to keep this class from being creatable outside of this assembly
|
||||
/// </summary>
|
||||
internal EdmToObjectNamespaceMap()
|
||||
{
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "edm")]
|
||||
public void Add(string edmNamespace, string objectNamespace)
|
||||
{
|
||||
EDesignUtil.CheckStringArgument(edmNamespace, "edmNamespace");
|
||||
EDesignUtil.CheckArgumentNull(objectNamespace, "objectNamespace");
|
||||
|
||||
_map.Add(edmNamespace, objectNamespace);
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "edm")]
|
||||
public bool Contains(string edmNamespace)
|
||||
{
|
||||
return _map.ContainsKey(edmNamespace);
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Edm")]
|
||||
public ICollection<string> EdmNamespaces
|
||||
{
|
||||
get { return _map.Keys; }
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "edm")]
|
||||
public bool Remove(string edmNamespace)
|
||||
{
|
||||
return _map.Remove(edmNamespace);
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "edm")]
|
||||
public bool TryGetObjectNamespace(string edmNamespace, out string objectNamespace)
|
||||
{
|
||||
return _map.TryGetValue(edmNamespace, out objectNamespace);
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "edm")]
|
||||
public string this[string edmNamespace]
|
||||
{
|
||||
get
|
||||
{
|
||||
return _map[edmNamespace];
|
||||
}
|
||||
set
|
||||
{
|
||||
_map[edmNamespace] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_map.Clear();
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get { return _map.Count; }
|
||||
}
|
||||
|
||||
internal Dictionary<string, string> AsDictionary()
|
||||
{
|
||||
return _map;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
//---------------------------------------------------------------------
|
||||
// <copyright file="AssociationTypeEmitter.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//
|
||||
// @owner [....]
|
||||
// @backupOwner [....]
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.CodeDom;
|
||||
using System.Data;
|
||||
using System.Data.Metadata.Edm;
|
||||
using System.Data.EntityModel.SchemaObjectModel;
|
||||
using System.Diagnostics;
|
||||
|
||||
|
||||
namespace System.Data.EntityModel.Emitters
|
||||
{
|
||||
/// <summary>
|
||||
/// Summary description for NestedTypeEmitter.
|
||||
/// </summary>
|
||||
internal sealed class AssociationTypeEmitter : SchemaTypeEmitter
|
||||
{
|
||||
public AssociationTypeEmitter(ClientApiGenerator generator, AssociationType associationType)
|
||||
: base(generator, associationType)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public override CodeTypeDeclarationCollection EmitApiClass()
|
||||
{
|
||||
Debug.Assert(Item.AssociationEndMembers.Count == 2, "must have exactly two ends");
|
||||
|
||||
AssociationEndMember end1 = Item.AssociationEndMembers[0];
|
||||
AssociationEndMember end2 = Item.AssociationEndMembers[1];
|
||||
|
||||
Generator.CompileUnit.AssemblyCustomAttributes.Add(
|
||||
AttributeEmitter.EmitSimpleAttribute(
|
||||
Utils.FQAdoFrameworkDataClassesName("EdmRelationshipAttribute"),
|
||||
Item.NamespaceName, //it is ok to use the c namespace because relationships aren't backed by clr objects
|
||||
Item.Name,
|
||||
end1.Name,
|
||||
GetMultiplicityCodeExpression(end1.RelationshipMultiplicity),
|
||||
GetEndTypeCodeExpression(end1),
|
||||
end2.Name,
|
||||
GetMultiplicityCodeExpression(end2.RelationshipMultiplicity),
|
||||
GetEndTypeCodeExpression(end2)
|
||||
));
|
||||
|
||||
// this method doesn't actually create a new type, just a new assembly level attribute for each end
|
||||
return new CodeTypeDeclarationCollection();
|
||||
}
|
||||
|
||||
private CodeTypeOfExpression GetEndTypeCodeExpression(AssociationEndMember end)
|
||||
{
|
||||
return new CodeTypeOfExpression(Generator.GetFullyQualifiedTypeReference(((RefType)end.TypeUsage.EdmType).ElementType));
|
||||
}
|
||||
|
||||
private CodeExpression GetMultiplicityCodeExpression(RelationshipMultiplicity multiplicity)
|
||||
{
|
||||
// example:
|
||||
// [System.Data.Objects.DataClasses.EdmRelationshipRoleAttribute("CustomerOrder", "Customer", global::System.Data.Metadata.Edm.RelationshipMultiplicity.One, typeof(Customer))]
|
||||
string roleMultiplicity = multiplicity.ToString();
|
||||
CodeExpression roleMultiplicityExpression = Emitter.EmitEnumMemberExpression(
|
||||
TypeReference.AdoFrameworkMetadataEdmType("RelationshipMultiplicity"), roleMultiplicity);
|
||||
return roleMultiplicityExpression;
|
||||
}
|
||||
|
||||
internal new AssociationType Item
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.Item as AssociationType;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,403 @@
|
||||
//---------------------------------------------------------------------
|
||||
// <copyright file="AttributeEmitter.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//
|
||||
// @owner [....]
|
||||
// @backupOwner [....]
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
using System.CodeDom;
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Data.SqlTypes;
|
||||
using System.Data.Metadata.Edm;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Entity.Design;
|
||||
using System.Data.Entity.Design.Common;
|
||||
using System.Data.EntityModel.SchemaObjectModel;
|
||||
using System.Data.Entity.Design.SsdlGenerator;
|
||||
using System.Globalization;
|
||||
|
||||
|
||||
namespace System.Data.EntityModel.Emitters
|
||||
{
|
||||
/// <summary>
|
||||
/// Summary description for AttributeEmitter.
|
||||
/// </summary>
|
||||
internal sealed class AttributeEmitter
|
||||
{
|
||||
TypeReference _typeReference;
|
||||
|
||||
internal TypeReference TypeReference
|
||||
{
|
||||
get { return _typeReference; }
|
||||
}
|
||||
|
||||
static readonly string AdoAttributeDataClassesNamespace = "System.Data.Objects.DataClasses";
|
||||
internal AttributeEmitter(TypeReference typeReference)
|
||||
{
|
||||
_typeReference = typeReference;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The method to be called to create the type level attributes for the ItemTypeEmitter
|
||||
/// </summary>
|
||||
/// <param name="emitter">The strongly typed emitter</param>
|
||||
/// <param name="typeDecl">The type declaration to add the attribues to.</param>
|
||||
public void EmitTypeAttributes(EntityTypeEmitter emitter, CodeTypeDeclaration typeDecl)
|
||||
{
|
||||
Debug.Assert(emitter != null, "emitter should not be null");
|
||||
Debug.Assert(typeDecl != null, "typeDecl should not be null");
|
||||
|
||||
EmitSchemaTypeAttribute(FQAdoFrameworkDataClassesName("EdmEntityTypeAttribute"), emitter, typeDecl);
|
||||
|
||||
CodeAttributeDeclaration attribute2 = EmitSimpleAttribute("System.Runtime.Serialization.DataContractAttribute");
|
||||
AttributeEmitter.AddNamedAttributeArguments(attribute2,
|
||||
"IsReference", true);
|
||||
typeDecl.CustomAttributes.Add(attribute2);
|
||||
|
||||
CodeAttributeDeclaration attribute3 = EmitSimpleAttribute("System.Serializable");
|
||||
typeDecl.CustomAttributes.Add(attribute3);
|
||||
|
||||
EmitKnownTypeAttributes(emitter.Item, emitter.Generator, typeDecl);
|
||||
}
|
||||
|
||||
private void EmitKnownTypeAttributes(EdmType baseType, ClientApiGenerator generator, CodeTypeDeclaration typeDecl)
|
||||
{
|
||||
foreach (EdmType edmType in generator.GetDirectSubTypes(baseType))
|
||||
{
|
||||
Debug.Assert(edmType.BaseType == baseType, "The types must be directly derived from basetype");
|
||||
|
||||
CodeTypeReference subTypeRef;
|
||||
if (generator.Language == LanguageOption.GenerateCSharpCode)
|
||||
{
|
||||
bool useGlobalPrefix = true;
|
||||
subTypeRef = generator.GetFullyQualifiedTypeReference(edmType, useGlobalPrefix);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Assert(generator.Language == LanguageOption.GenerateVBCode, "Did you add a new language?");
|
||||
subTypeRef = generator.GetLeastPossibleQualifiedTypeReference(edmType);
|
||||
}
|
||||
CodeAttributeDeclaration attribute = EmitSimpleAttribute("System.Runtime.Serialization.KnownTypeAttribute", new CodeTypeOfExpression(subTypeRef));
|
||||
typeDecl.CustomAttributes.Add(attribute);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The method to be called to create the type level attributes for the StructuredTypeEmitter
|
||||
/// </summary>
|
||||
/// <param name="emitter">The strongly typed emitter</param>
|
||||
/// <param name="typeDecl">The type declaration to add the attribues to.</param>
|
||||
public void EmitTypeAttributes(StructuredTypeEmitter emitter, CodeTypeDeclaration typeDecl)
|
||||
{
|
||||
Debug.Assert(emitter != null, "emitter should not be null");
|
||||
Debug.Assert(typeDecl != null, "typeDecl should not be null");
|
||||
|
||||
// nothing to do here yet
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The method to be called to create the type level attributes for the SchemaTypeEmitter
|
||||
/// </summary>
|
||||
/// <param name="emitter">The strongly typed emitter</param>
|
||||
/// <param name="typeDecl">The type declaration to add the attribues to.</param>
|
||||
public void EmitTypeAttributes(SchemaTypeEmitter emitter, CodeTypeDeclaration typeDecl)
|
||||
{
|
||||
Debug.Assert(emitter != null, "emitter should not be null");
|
||||
Debug.Assert(typeDecl != null, "typeDecl should not be null");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Common way to fill out EdmTypeAttribute derived attributes
|
||||
/// </summary>
|
||||
/// <param name="attributeName">Unqualified name of the attribute</param>
|
||||
/// <param name="emitter">The strongly typed emitter</param>
|
||||
/// <param name="typeDecl">The type declaration to add the attribues to.</param>
|
||||
public void EmitSchemaTypeAttribute(string attributeName, SchemaTypeEmitter emitter, CodeTypeDeclaration typeDecl)
|
||||
{
|
||||
// call the shared static version
|
||||
EdmType type = emitter.Item as EdmType;
|
||||
Debug.Assert(type != null, "type is not an EdmType");
|
||||
EmitSchemaTypeAttribute(attributeName, type, typeDecl as CodeTypeMember);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shared code for adding a EdmTypeAttribute derived attribute including parameters to a type or property
|
||||
/// </summary>
|
||||
/// <param name="attributeName">Unqualified name of the attribute</param>
|
||||
/// <param name="type">The type or property type of the code that is having the attribute attached.</param>
|
||||
/// <param name="member">The type declaration to add the attribues to.</param>
|
||||
public void EmitSchemaTypeAttribute(string attributeName, EdmType type, CodeTypeMember member)
|
||||
{
|
||||
Debug.Assert(attributeName != null, "attributeName should not be null");
|
||||
Debug.Assert(type != null, "type should not be null");
|
||||
Debug.Assert(member != null, "typeDecl should not be null");
|
||||
|
||||
// [mappingattribute(SchemaName="namespace",TypeName="classname")
|
||||
CodeAttributeDeclaration attribute = EmitSimpleAttribute(attributeName);
|
||||
AttributeEmitter.AddNamedAttributeArguments(attribute,
|
||||
"NamespaceName", type.NamespaceName,
|
||||
"Name", type.Name);
|
||||
|
||||
member.CustomAttributes.Add(attribute);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Emit the attributes for the new navigation property
|
||||
/// </summary>
|
||||
/// <param name="generator">The ClientApiGenerator instance</param>
|
||||
/// <param name="targetRelationshipEnd">The relationship end that is being targeted</param>
|
||||
/// <param name="propertyDecl">The property declaration to attach the attribute to.</param>
|
||||
/// <param name="additionalAttributes">Additional attributes</param>
|
||||
public void EmitNavigationPropertyAttributes(ClientApiGenerator generator,
|
||||
RelationshipEndMember targetRelationshipEnd,
|
||||
CodeMemberProperty propertyDecl,
|
||||
List<CodeAttributeDeclaration> additionalAttributes)
|
||||
{
|
||||
CodeAttributeDeclaration attribute = EmitSimpleAttribute(FQAdoFrameworkDataClassesName("EdmRelationshipNavigationPropertyAttribute"),
|
||||
targetRelationshipEnd.DeclaringType.NamespaceName,
|
||||
targetRelationshipEnd.DeclaringType.Name,
|
||||
targetRelationshipEnd.Name);
|
||||
|
||||
propertyDecl.CustomAttributes.Add(attribute);
|
||||
EmitGeneratedCodeAttribute(propertyDecl);
|
||||
if (additionalAttributes != null && additionalAttributes.Count > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
propertyDecl.CustomAttributes.AddRange(additionalAttributes.ToArray());
|
||||
}
|
||||
catch (ArgumentNullException e)
|
||||
{
|
||||
generator.AddError(Strings.InvalidAttributeSuppliedForProperty(propertyDecl.Name),
|
||||
ModelBuilderErrorCode.InvalidAttributeSuppliedForProperty,
|
||||
EdmSchemaErrorSeverity.Error,
|
||||
e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
// Emit
|
||||
// [global::System.CodeDom.Compiler.GeneratedCode("System.Data.Entity.Design.EntityClassGenerator", "4.0.0.0")]
|
||||
//
|
||||
// this allows FxCop to skip analysis of these methods and types, it should not be applied to partial types, only the
|
||||
// generated members of partial types
|
||||
//
|
||||
CodeAttributeDeclaration _GeneratedCodeAttribute;
|
||||
internal void EmitGeneratedCodeAttribute(CodeTypeMember member)
|
||||
{
|
||||
if(_GeneratedCodeAttribute == null)
|
||||
{
|
||||
_GeneratedCodeAttribute = EmitSimpleAttribute("System.CodeDom.Compiler.GeneratedCode",
|
||||
"System.Data.Entity.Design.EntityClassGenerator",
|
||||
typeof(EntityClassGenerator).Assembly.GetName().Version.ToString());
|
||||
|
||||
}
|
||||
|
||||
member.CustomAttributes.Add(_GeneratedCodeAttribute);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The method to be called to create the property level attributes for the PropertyEmitter
|
||||
/// </summary>
|
||||
/// <param name="emitter">The strongly typed emitter</param>
|
||||
/// <param name="propertyDecl">The type declaration to add the attribues to.</param>
|
||||
/// <param name="additionalAttributes">Additional attributes to emit</param>
|
||||
public void EmitPropertyAttributes(PropertyEmitter emitter,
|
||||
CodeMemberProperty propertyDecl,
|
||||
List<CodeAttributeDeclaration> additionalAttributes)
|
||||
{
|
||||
if (MetadataUtil.IsPrimitiveType(emitter.Item.TypeUsage.EdmType) || MetadataUtil.IsEnumerationType(emitter.Item.TypeUsage.EdmType))
|
||||
{
|
||||
CodeAttributeDeclaration scalarPropertyAttribute = EmitSimpleAttribute(FQAdoFrameworkDataClassesName("EdmScalarPropertyAttribute"));
|
||||
|
||||
if (emitter.IsKeyProperty)
|
||||
{
|
||||
Debug.Assert(emitter.Item.Nullable == false, "An EntityKeyProperty cannot be nullable.");
|
||||
|
||||
AttributeEmitter.AddNamedAttributeArguments(scalarPropertyAttribute, "EntityKeyProperty", true);
|
||||
}
|
||||
|
||||
if (!emitter.Item.Nullable)
|
||||
{
|
||||
AttributeEmitter.AddNamedAttributeArguments(scalarPropertyAttribute, "IsNullable", false);
|
||||
}
|
||||
|
||||
propertyDecl.CustomAttributes.Add(scalarPropertyAttribute);
|
||||
}
|
||||
else //Complex property
|
||||
{
|
||||
Debug.Assert(MetadataUtil.IsComplexType(emitter.Item.TypeUsage.EdmType) ||
|
||||
(MetadataUtil.IsCollectionType(emitter.Item.TypeUsage.EdmType)),
|
||||
"not a complex type or a collection type");
|
||||
CodeAttributeDeclaration attribute = EmitSimpleAttribute(FQAdoFrameworkDataClassesName("EdmComplexPropertyAttribute"));
|
||||
propertyDecl.CustomAttributes.Add(attribute);
|
||||
|
||||
// Have CodeDOM serialization set the properties on the ComplexObject, not the ComplexObject instance.
|
||||
attribute = EmitSimpleAttribute("System.ComponentModel.DesignerSerializationVisibility");
|
||||
AttributeEmitter.AddAttributeArguments(attribute,
|
||||
new object[] { new CodePropertyReferenceExpression(
|
||||
new CodeTypeReferenceExpression(TypeReference.ForType(
|
||||
typeof(System.ComponentModel.DesignerSerializationVisibility))),"Content") });
|
||||
propertyDecl.CustomAttributes.Add(attribute);
|
||||
|
||||
if (!MetadataUtil.IsCollectionType(emitter.Item.TypeUsage.EdmType))
|
||||
{
|
||||
// Non-collection complex properties also need additional serialization attributes to force them to be explicitly serialized if they are null
|
||||
// If this is omitted, null complex properties do not get explicitly set to null during deserialization, which causes
|
||||
// them to be lazily constructed once the property is accessed after the entity is deserialized. If the property is
|
||||
// actually null during serialiation, that means the user has explicitly set it, so we need to maintain that during serialization.
|
||||
// This doesn't apply to collection types because they aren't lazily constructed and don't need this extra information.
|
||||
attribute = EmitSimpleAttribute("System.Xml.Serialization.XmlElement");
|
||||
AttributeEmitter.AddNamedAttributeArguments(attribute, "IsNullable", true);
|
||||
propertyDecl.CustomAttributes.Add(attribute);
|
||||
|
||||
attribute = EmitSimpleAttribute("System.Xml.Serialization.SoapElement");
|
||||
AttributeEmitter.AddNamedAttributeArguments(attribute, "IsNullable", true);
|
||||
propertyDecl.CustomAttributes.Add(attribute);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// serialization attribute
|
||||
AddDataMemberAttribute(propertyDecl);
|
||||
|
||||
if (additionalAttributes != null && additionalAttributes.Count > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
propertyDecl.CustomAttributes.AddRange(additionalAttributes.ToArray());
|
||||
}
|
||||
catch (ArgumentNullException e)
|
||||
{
|
||||
emitter.Generator.AddError(Strings.InvalidAttributeSuppliedForProperty(emitter.Item.Name),
|
||||
ModelBuilderErrorCode.InvalidAttributeSuppliedForProperty,
|
||||
EdmSchemaErrorSeverity.Error,
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
EmitGeneratedCodeAttribute(propertyDecl);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The method to be called to create the type level attributes for the NestedTypeEmitter
|
||||
/// </summary>
|
||||
/// <param name="emitter">The strongly typed emitter</param>
|
||||
/// <param name="typeDecl">The type declaration to add the attribues to.</param>
|
||||
public void EmitTypeAttributes(ComplexTypeEmitter emitter, CodeTypeDeclaration typeDecl)
|
||||
{
|
||||
Debug.Assert(emitter != null, "emitter should not be null");
|
||||
Debug.Assert(typeDecl != null, "typeDecl should not be null");
|
||||
|
||||
EmitSchemaTypeAttribute(FQAdoFrameworkDataClassesName("EdmComplexTypeAttribute"),
|
||||
emitter, typeDecl);
|
||||
|
||||
CodeAttributeDeclaration attribute = EmitSimpleAttribute("System.Runtime.Serialization.DataContractAttribute");
|
||||
AttributeEmitter.AddNamedAttributeArguments(attribute,
|
||||
"IsReference", true);
|
||||
typeDecl.CustomAttributes.Add(attribute);
|
||||
|
||||
CodeAttributeDeclaration attribute2 = EmitSimpleAttribute("System.Serializable");
|
||||
typeDecl.CustomAttributes.Add(attribute2);
|
||||
|
||||
EmitKnownTypeAttributes(emitter.Item, emitter.Generator, typeDecl);
|
||||
}
|
||||
|
||||
#region Static Methods
|
||||
/// <summary>
|
||||
/// Returns the name qualified with the Ado.Net EDM DataClasses Attribute namespace
|
||||
/// </summary>
|
||||
/// <param name="unqualifiedName"></param>
|
||||
/// <returns></returns>
|
||||
public static string FQAdoFrameworkDataClassesName(string unqualifiedName)
|
||||
{
|
||||
return AdoAttributeDataClassesNamespace + "." + unqualifiedName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="attributeType"></param>
|
||||
/// <param name="arguments"></param>
|
||||
/// <returns></returns>
|
||||
public CodeAttributeDeclaration EmitSimpleAttribute(string attributeType, params object[] arguments)
|
||||
{
|
||||
CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(TypeReference.FromString(attributeType, true));
|
||||
|
||||
AddAttributeArguments(attribute, arguments);
|
||||
|
||||
return attribute;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="attribute"></param>
|
||||
/// <param name="arguments"></param>
|
||||
public static void AddAttributeArguments(CodeAttributeDeclaration attribute, object[] arguments)
|
||||
{
|
||||
foreach (object argument in arguments)
|
||||
{
|
||||
CodeExpression expression = argument as CodeExpression;
|
||||
if (expression == null)
|
||||
expression = new CodePrimitiveExpression(argument);
|
||||
attribute.Arguments.Add(new CodeAttributeArgument(expression));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="attribute"></param>
|
||||
/// <param name="arguments"></param>
|
||||
public static void AddNamedAttributeArguments(CodeAttributeDeclaration attribute, params object[] arguments)
|
||||
{
|
||||
for (int i = 1; i < arguments.Length; i += 2)
|
||||
{
|
||||
CodeExpression expression = arguments[i] as CodeExpression;
|
||||
if (expression == null)
|
||||
expression = new CodePrimitiveExpression(arguments[i]);
|
||||
attribute.Arguments.Add(new CodeAttributeArgument(arguments[i - 1].ToString(), expression));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an XmlIgnore attribute to the given property declaration. This is
|
||||
/// used to explicitly skip certain properties during XML serialization.
|
||||
/// </summary>
|
||||
/// <param name="propertyDecl">the property to mark with XmlIgnore</param>
|
||||
public void AddIgnoreAttributes(CodeMemberProperty propertyDecl)
|
||||
{
|
||||
CodeAttributeDeclaration xmlIgnoreAttribute = EmitSimpleAttribute(typeof(System.Xml.Serialization.XmlIgnoreAttribute).FullName);
|
||||
CodeAttributeDeclaration soapIgnoreAttribute = EmitSimpleAttribute(typeof(System.Xml.Serialization.SoapIgnoreAttribute).FullName);
|
||||
propertyDecl.CustomAttributes.Add(xmlIgnoreAttribute);
|
||||
propertyDecl.CustomAttributes.Add(soapIgnoreAttribute);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an Browsable(false) attribute to the given property declaration.
|
||||
/// This is used to explicitly avoid display property in the PropertyGrid.
|
||||
/// </summary>
|
||||
/// <param name="propertyDecl">the property to mark with XmlIgnore</param>
|
||||
public void AddBrowsableAttribute(CodeMemberProperty propertyDecl)
|
||||
{
|
||||
CodeAttributeDeclaration browsableAttribute = EmitSimpleAttribute(typeof(System.ComponentModel.BrowsableAttribute).FullName, false);
|
||||
propertyDecl.CustomAttributes.Add(browsableAttribute);
|
||||
}
|
||||
|
||||
public void AddDataMemberAttribute(CodeMemberProperty propertyDecl)
|
||||
{
|
||||
CodeAttributeDeclaration browsableAttribute = EmitSimpleAttribute("System.Runtime.Serialization.DataMemberAttribute");
|
||||
propertyDecl.CustomAttributes.Add(browsableAttribute);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,347 @@
|
||||
//---------------------------------------------------------------------
|
||||
// <copyright file="CommentEmitter.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//
|
||||
// @owner [....]
|
||||
// @backupOwner [....]
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.CodeDom;
|
||||
using System.Diagnostics;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Data;
|
||||
using System.Data.Common.Utils;
|
||||
using System.Data.EntityModel.SchemaObjectModel;
|
||||
using System.Globalization;
|
||||
using System.Data.Entity.Design.Common;
|
||||
using System.Data.Entity.Design;
|
||||
using System.Data.Metadata.Edm;
|
||||
using System.Reflection;
|
||||
using System.Xml;
|
||||
using System.IO;
|
||||
|
||||
|
||||
namespace System.Data.EntityModel.Emitters
|
||||
{
|
||||
/// <summary>
|
||||
/// static helper class for emitting comments.
|
||||
/// </summary>
|
||||
internal static class CommentEmitter
|
||||
{
|
||||
#region Static Fields
|
||||
private static readonly Regex LeadingBlanks = new Regex(@"^(?<LeadingBlanks>\s{1,})\S", RegexOptions.Singleline | RegexOptions.Compiled);
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// emit all the documentation comments for an element's documentation child
|
||||
/// (if the element does not have a documentation child emit some standard "missing comments" comment
|
||||
/// </summary>
|
||||
/// <param name="element">the element whose documentation is to be displayed</param>
|
||||
/// <param name="commentCollection">the comment collection of the CodeDom object to be commented</param>
|
||||
public static void EmitSummaryComments(MetadataItem item, CodeCommentStatementCollection commentCollection)
|
||||
{
|
||||
Debug.Assert(item != null, "item parameter is null");
|
||||
Debug.Assert(commentCollection != null, "commentCollection parameter is null");
|
||||
|
||||
Documentation documentation = GetDocumentation(item);
|
||||
string [] summaryComments = null;
|
||||
if (documentation != null && !MetadataUtil.IsNullOrEmptyOrWhiteSpace(documentation.Summary))
|
||||
{
|
||||
// we have documentation to emit
|
||||
summaryComments = GetFormattedLines(documentation.Summary, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
string summaryComment;
|
||||
// no summary content, so use a default
|
||||
switch (item.BuiltInTypeKind)
|
||||
{
|
||||
case BuiltInTypeKind.EdmProperty:
|
||||
summaryComment = Strings.MissingPropertyDocumentation(((EdmProperty)item).Name);
|
||||
break;
|
||||
case BuiltInTypeKind.ComplexType:
|
||||
summaryComment = Strings.MissingComplexTypeDocumentation(((ComplexType)item).FullName);
|
||||
break;
|
||||
default:
|
||||
{
|
||||
PropertyInfo pi = item.GetType().GetProperty("FullName");
|
||||
if (pi == null)
|
||||
{
|
||||
pi = item.GetType().GetProperty("Name");
|
||||
}
|
||||
|
||||
object value = null;
|
||||
if (pi != null)
|
||||
{
|
||||
value = pi.GetValue(item, null);
|
||||
}
|
||||
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
summaryComment = Strings.MissingDocumentation(value.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
summaryComment = Strings.MissingDocumentationNoName;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
summaryComments = new string[] { summaryComment };
|
||||
}
|
||||
EmitSummaryComments(summaryComments, commentCollection);
|
||||
EmitOtherDocumentationComments(documentation, commentCollection);
|
||||
}
|
||||
|
||||
private static Documentation GetDocumentation(MetadataItem item)
|
||||
{
|
||||
if (item is Documentation)
|
||||
return (Documentation)item;
|
||||
else
|
||||
return item.Documentation;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Emit summary comments from a string
|
||||
/// </summary>
|
||||
/// <param name="summaryComments">the summary comments to be emitted</param>
|
||||
/// <param name="commentCollection">the comment collection of the CodeDom object to be commented</param>
|
||||
public static void EmitSummaryComments(string summaryComments, CodeCommentStatementCollection commentCollection)
|
||||
{
|
||||
Debug.Assert(commentCollection != null, "commentCollection parameter is null");
|
||||
|
||||
if (string.IsNullOrEmpty(summaryComments) || string.IsNullOrEmpty(summaryComments = summaryComments.TrimEnd()))
|
||||
return;
|
||||
|
||||
EmitSummaryComments(SplitIntoLines(summaryComments), commentCollection);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Emit some lines of comments
|
||||
/// </summary>
|
||||
/// <param name="commentLines">the lines of comments to emit</param>
|
||||
/// <param name="commentCollection">the comment collection of the CodeDom object to be commented</param>
|
||||
/// <param name="docComment">true if the comments are 'documentation' comments</param>
|
||||
public static void EmitComments(string[] commentLines, CodeCommentStatementCollection commentCollection, bool docComment)
|
||||
{
|
||||
Debug.Assert(commentLines != null, "commentLines parameter is null");
|
||||
Debug.Assert(commentCollection != null, "commentCollection parameter is null");
|
||||
|
||||
foreach (string comment in commentLines)
|
||||
{
|
||||
commentCollection.Add(new CodeCommentStatement(comment, docComment));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Emit documentation comments for a method parameter
|
||||
/// </summary>
|
||||
/// <param name="parameter">the parameter being commented</param>
|
||||
/// <param name="comment">the comment text</param>
|
||||
/// <param name="commentCollection">the comment collection of the CodeDom object to be commented</param>
|
||||
public static void EmitParamComments(CodeParameterDeclarationExpression parameter, string comment,
|
||||
CodeCommentStatementCollection commentCollection)
|
||||
{
|
||||
Debug.Assert(parameter != null, "parameter parameter is null");
|
||||
Debug.Assert(comment != null, "comment parameter is null");
|
||||
|
||||
string paramComment = string.Format(System.Globalization.CultureInfo.CurrentCulture,
|
||||
"<param name=\"{0}\">{1}</param>", parameter.Name, comment);
|
||||
commentCollection.Add(new CodeCommentStatement(paramComment, true));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 'Format' a string of text into lines: separates in to lines on '\n', removes '\r', and removes common leading blanks.
|
||||
/// </summary>
|
||||
/// <param name="escapeForXml">if true characters troublesome for xml are converted to entities</param>
|
||||
/// <param name="text">the text to be formatted</param>
|
||||
/// <returns>the formatted lines</returns>
|
||||
public static string[] GetFormattedLines(string text, bool escapeForXml)
|
||||
{
|
||||
#if false
|
||||
if ( text.IndexOf("\n") >= 0 )
|
||||
Console.WriteLine("GetFormattedText(\""+text.Replace("\n","\\n").Replace("\r","\\r")+"\","+escapeForXml+")");
|
||||
#endif
|
||||
Debug.Assert(!string.IsNullOrEmpty(text));
|
||||
|
||||
// nothing in, almost nothing out.
|
||||
if (StringUtil.IsNullOrEmptyOrWhiteSpace(text))
|
||||
return new string[] { "" };
|
||||
|
||||
// normalize CRLF and LFCRs to LFs (we just remove all the crs, assuming there are no extraneous ones) and remove trailing spaces
|
||||
text = text.Replace("\r", "");
|
||||
|
||||
// remove leading and.or trailing line ends to get single line for:
|
||||
// <documentation>
|
||||
// text
|
||||
// <documentation>
|
||||
bool trim = false;
|
||||
int start = text.IndexOf('\n');
|
||||
if (start >= 0 && MetadataUtil.IsNullOrEmptyOrWhiteSpace(text, 0, start + 1))
|
||||
{
|
||||
++start;
|
||||
trim = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
start = 0;
|
||||
}
|
||||
int last = text.LastIndexOf('\n');
|
||||
if (last > start - 1 && MetadataUtil.IsNullOrEmptyOrWhiteSpace(text, last))
|
||||
{
|
||||
--last;
|
||||
trim = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
last = text.Length - 1;
|
||||
}
|
||||
if (trim)
|
||||
{
|
||||
Debug.Assert(start <= last);
|
||||
text = text.Substring(start, last - start + 1);
|
||||
}
|
||||
|
||||
// break into lines (preversing blank lines and preping text for being in xml comments)
|
||||
if (escapeForXml)
|
||||
text = MetadataUtil.Entityize(text);
|
||||
string[] lines = SplitIntoLines(text);
|
||||
|
||||
if (lines.Length == 1)
|
||||
{
|
||||
lines[0] = lines[0].Trim();
|
||||
return lines;
|
||||
}
|
||||
|
||||
// find the maximum leading whitespace substring (ignoring blank lines)
|
||||
string leadingBlanks = null;
|
||||
foreach (string line in lines)
|
||||
{
|
||||
// is an empty line
|
||||
if (MetadataUtil.IsNullOrEmptyOrWhiteSpace(line))
|
||||
continue;
|
||||
|
||||
// find the leading whitespace substring
|
||||
Match match = LeadingBlanks.Match(line);
|
||||
if (!match.Success)
|
||||
{
|
||||
//none, we're done
|
||||
leadingBlanks = "";
|
||||
break;
|
||||
}
|
||||
|
||||
if (leadingBlanks == null)
|
||||
{
|
||||
// this is first non-empty line
|
||||
leadingBlanks = match.Groups["LeadingBlanks"].Value;
|
||||
continue;
|
||||
}
|
||||
|
||||
// use the leadingBlanks if it matched the new one or it is a leading substring of the new one
|
||||
string leadingBlanks2 = match.Groups["LeadingBlanks"].Value;
|
||||
if (leadingBlanks2 == leadingBlanks || leadingBlanks2.StartsWith(leadingBlanks, StringComparison.Ordinal))
|
||||
continue;
|
||||
|
||||
if (leadingBlanks.StartsWith(leadingBlanks2, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// the current leading whitespace string is a leading substring of leadingBlanks. use the new one
|
||||
leadingBlanks = leadingBlanks2;
|
||||
continue;
|
||||
}
|
||||
|
||||
// find longest leading common substring and use that.
|
||||
int minLength = Math.Min(leadingBlanks.Length, leadingBlanks2.Length);
|
||||
for (int j = 0; j < minLength; ++j)
|
||||
{
|
||||
if (leadingBlanks[j] != leadingBlanks2[j])
|
||||
{
|
||||
if (j == 0)
|
||||
leadingBlanks = "";
|
||||
else
|
||||
leadingBlanks = leadingBlanks.Substring(0, j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if we've reduced the leading substring to an empty string, we're done.
|
||||
if (string.IsNullOrEmpty(leadingBlanks))
|
||||
break;
|
||||
}
|
||||
|
||||
// remove the leading whitespace substring and remove any trailing blanks.
|
||||
int numLeadingCharsToRemove = leadingBlanks.Length;
|
||||
for (int i = 0; i < lines.Length; ++i)
|
||||
{
|
||||
if (lines[i].Length >= numLeadingCharsToRemove)
|
||||
lines[i] = lines[i].Substring(numLeadingCharsToRemove);
|
||||
lines[i] = lines[i].TrimEnd();
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
/// <summary>
|
||||
/// Emit the other (than Summary) documentation comments from a Documentation element
|
||||
/// </summary>
|
||||
/// <param name="documentation">the schema Docuementation element</param>
|
||||
/// <param name="commentCollection">the comment collection of the CodeDom object to be commented</param>
|
||||
private static void EmitOtherDocumentationComments(Documentation documentation, CodeCommentStatementCollection commentCollection)
|
||||
{
|
||||
Debug.Assert(commentCollection != null);
|
||||
if (documentation == null)
|
||||
return;
|
||||
|
||||
if (!string.IsNullOrEmpty(documentation.LongDescription))
|
||||
EmitXmlComments("LongDescription", GetFormattedLines(documentation.LongDescription, true), commentCollection);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Emit the summary comments
|
||||
/// </summary>
|
||||
/// <param name="summaryComments"></param>
|
||||
/// <param name="commentCollection">the comment collection of the CodeDom object to be commented</param>
|
||||
private static void EmitSummaryComments(string[] summaryComments, CodeCommentStatementCollection commentCollection)
|
||||
{
|
||||
Debug.Assert(summaryComments != null);
|
||||
Debug.Assert(commentCollection != null);
|
||||
|
||||
EmitXmlComments("summary", summaryComments, commentCollection);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// emit documentation comments between xml open and close tags
|
||||
/// </summary>
|
||||
/// <param name="tag">the xml tag name</param>
|
||||
/// <param name="summaryComments">the lines of comments to emit</param>
|
||||
/// <param name="commentCollection">the comment collection of the CodeDom object to be commented</param>
|
||||
private static void EmitXmlComments(string tag, string[] summaryComments, CodeCommentStatementCollection commentCollection)
|
||||
{
|
||||
Debug.Assert(tag != null);
|
||||
Debug.Assert(summaryComments != null);
|
||||
Debug.Assert(commentCollection != null);
|
||||
|
||||
commentCollection.Add(new CodeCommentStatement(string.Format(CultureInfo.InvariantCulture, "<{0}>", tag), true));
|
||||
EmitComments(summaryComments, commentCollection, true);
|
||||
commentCollection.Add(new CodeCommentStatement(string.Format(CultureInfo.InvariantCulture, "</{0}>", tag), true));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// split a string into lines on '\n' chars and remove '\r' chars
|
||||
/// </summary>
|
||||
/// <param name="text">the string to split</param>
|
||||
/// <returns>the split string</returns>
|
||||
private static string[] SplitIntoLines(string text)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text))
|
||||
return new string[] { "" };
|
||||
|
||||
return text.Replace("\r", "").Split('\n');
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
//---------------------------------------------------------------------
|
||||
// <copyright file="ComplexTypeEmitter.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//
|
||||
// @owner [....]
|
||||
// @backupOwner [....]
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.CodeDom;
|
||||
using System.Data;
|
||||
using System.Data.Metadata.Edm;
|
||||
using System.Data.EntityModel.SchemaObjectModel;
|
||||
|
||||
|
||||
namespace System.Data.EntityModel.Emitters
|
||||
{
|
||||
/// <summary>
|
||||
/// Summary description for NestedTypeEmitter.
|
||||
/// </summary>
|
||||
internal sealed class ComplexTypeEmitter : StructuredTypeEmitter
|
||||
{
|
||||
#region Methods
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="generator"></param>
|
||||
/// <param name="nestedType"></param>
|
||||
public ComplexTypeEmitter(ClientApiGenerator generator, ComplexType complexType)
|
||||
: base(generator, complexType)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Apply the attributes to this type.
|
||||
/// </summary>
|
||||
/// <param name="typeDecl">The declaration of the type that should have attributes added to it.</param>
|
||||
protected override void EmitTypeAttributes( CodeTypeDeclaration typeDecl )
|
||||
{
|
||||
Generator.AttributeEmitter.EmitTypeAttributes( this, typeDecl );
|
||||
base.EmitTypeAttributes( typeDecl );
|
||||
}
|
||||
#endregion
|
||||
#region Protected Properties
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected override CodeTypeReference GetBaseType()
|
||||
{
|
||||
CodeTypeReference baseType = base.GetBaseType();
|
||||
if (baseType == null)
|
||||
{
|
||||
baseType = TypeReference.ComplexTypeBaseClass;
|
||||
}
|
||||
return baseType;
|
||||
}
|
||||
|
||||
protected override ReadOnlyMetadataCollection<EdmProperty> GetProperties()
|
||||
{
|
||||
return Item.Properties;
|
||||
}
|
||||
|
||||
internal new ComplexType Item
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.Item as ComplexType;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
//---------------------------------------------------------------------
|
||||
// <copyright file="Emitter.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//
|
||||
// @owner [....]
|
||||
// @backupOwner [....]
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.CodeDom;
|
||||
using System.Diagnostics;
|
||||
using System.Data.EntityModel.SchemaObjectModel;
|
||||
|
||||
|
||||
|
||||
|
||||
namespace System.Data.EntityModel.Emitters
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
internal abstract class Emitter
|
||||
{
|
||||
#region Instance Fields
|
||||
private ClientApiGenerator _generator = null;
|
||||
#endregion
|
||||
|
||||
#region Static Fields
|
||||
private static CodeExpression _nullExpression = null;
|
||||
private static CodeExpression _thisRef = null;
|
||||
|
||||
/// <summary>Name of property used to get StorageContext from an Entity</summary>
|
||||
private const string EntityGetContextPropertyName = "Context";
|
||||
/// <summary>Name of property used to get StorageContext from a StorageSearcher</summary>
|
||||
protected const string SearcherGetContextPropertyName = "Context";
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="generator"></param>
|
||||
protected Emitter(ClientApiGenerator generator)
|
||||
{
|
||||
Generator = generator;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="expression"></param>
|
||||
/// <returns></returns>
|
||||
protected static CodeBinaryOperatorExpression EmitExpressionEqualsNull(CodeExpression expression)
|
||||
{
|
||||
return new CodeBinaryOperatorExpression(expression, CodeBinaryOperatorType.IdentityEquality, NullExpression);
|
||||
}
|
||||
|
||||
protected static CodeBinaryOperatorExpression EmitExpressionDoesNotEqualNull(CodeExpression expression)
|
||||
{
|
||||
return new CodeBinaryOperatorExpression(expression, CodeBinaryOperatorType.IdentityInequality, NullExpression);
|
||||
}
|
||||
|
||||
internal static CodeExpression EmitEnumMemberExpression(CodeTypeReference type, string member)
|
||||
{
|
||||
CodeTypeReferenceExpression typeref = new CodeTypeReferenceExpression(type);
|
||||
return new CodeFieldReferenceExpression(typeref, member);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Protected Properties
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected static CodeExpression ThisRef
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_thisRef == null)
|
||||
_thisRef = new CodeThisReferenceExpression();
|
||||
return _thisRef;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
internal ClientApiGenerator Generator
|
||||
{
|
||||
get
|
||||
{
|
||||
return _generator;
|
||||
}
|
||||
private set
|
||||
{
|
||||
_generator = value;
|
||||
}
|
||||
}
|
||||
|
||||
protected TypeReference TypeReference
|
||||
{
|
||||
get
|
||||
{
|
||||
return _generator.TypeReference;
|
||||
}
|
||||
}
|
||||
|
||||
protected AttributeEmitter AttributeEmitter
|
||||
{
|
||||
get { return _generator.AttributeEmitter; }
|
||||
}
|
||||
|
||||
protected static CodeExpression NullExpression
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_nullExpression == null)
|
||||
_nullExpression = new CodePrimitiveExpression(null);
|
||||
|
||||
return _nullExpression;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,128 @@
|
||||
//---------------------------------------------------------------------
|
||||
// <copyright file="EntityTypeEmitter.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//
|
||||
// @owner [....]
|
||||
// @backupOwner [....]
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.CodeDom;
|
||||
using System.Data;
|
||||
using Som=System.Data.EntityModel.SchemaObjectModel;
|
||||
using System.Data.Metadata.Edm;
|
||||
|
||||
|
||||
namespace System.Data.EntityModel.Emitters
|
||||
{
|
||||
/// <summary>
|
||||
/// Summary description for ItemTypeEmitter.
|
||||
/// </summary>
|
||||
internal sealed class EntityTypeEmitter : StructuredTypeEmitter
|
||||
{
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="generator"></param>
|
||||
/// <param name="itemType"></param>
|
||||
public EntityTypeEmitter(ClientApiGenerator generator, EntityType entity)
|
||||
: base(generator, entity)
|
||||
{
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="typeDecl"></param>
|
||||
protected override void EmitProperties(CodeTypeDeclaration typeDecl)
|
||||
{
|
||||
base.EmitProperties(typeDecl);
|
||||
foreach ( NavigationProperty navigationProperty in Item.GetDeclaredOnlyMembers<NavigationProperty>() )
|
||||
{
|
||||
NavigationPropertyEmitter navigationPropertyEmitter = new NavigationPropertyEmitter(Generator, navigationProperty, UsingStandardBaseClass);
|
||||
navigationPropertyEmitter.Emit(typeDecl);
|
||||
}
|
||||
}
|
||||
|
||||
public override CodeTypeDeclarationCollection EmitApiClass()
|
||||
{
|
||||
CodeTypeDeclarationCollection typeDecls = base.EmitApiClass();
|
||||
|
||||
if ( Item.KeyMembers.Count > 0 && typeDecls.Count == 1 )
|
||||
{
|
||||
// generate xml comments for the key properties
|
||||
CodeTypeDeclaration typeDecl = typeDecls[0];
|
||||
typeDecl.Comments.Add( new CodeCommentStatement( "<KeyProperties>", true ) );
|
||||
foreach ( EdmMember keyProperty in Item.KeyMembers)
|
||||
{
|
||||
string name = keyProperty.Name;
|
||||
typeDecl.Comments.Add( new CodeCommentStatement( name, true ) );
|
||||
}
|
||||
typeDecl.Comments.Add( new CodeCommentStatement( "</KeyProperties>", true ) );
|
||||
}
|
||||
|
||||
return typeDecls;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="typeDecl"></param>
|
||||
protected override void EmitTypeAttributes(CodeTypeDeclaration typeDecl)
|
||||
{
|
||||
Generator.AttributeEmitter.EmitTypeAttributes( this, typeDecl );
|
||||
base.EmitTypeAttributes( typeDecl );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected override CodeTypeReference GetBaseType()
|
||||
{
|
||||
CodeTypeReference baseType = base.GetBaseType();
|
||||
if (baseType == null)
|
||||
{
|
||||
baseType = TypeReference.EntityTypeBaseClass;
|
||||
}
|
||||
return baseType;
|
||||
}
|
||||
|
||||
protected override ReadOnlyMetadataCollection<EdmProperty> GetProperties()
|
||||
{
|
||||
return Item.Properties;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Public Properties
|
||||
#endregion
|
||||
|
||||
#region Protected Properties
|
||||
#endregion
|
||||
|
||||
#region Private Properties
|
||||
/// <summary>
|
||||
/// Gets the SchemaElement that this class is generating code for.
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
public new EntityType Item
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.Item as EntityType;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,406 @@
|
||||
//---------------------------------------------------------------------
|
||||
// <copyright file="FixUp.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//
|
||||
// @owner [....]
|
||||
// @backupOwner [....]
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Data.EntityModel.SchemaObjectModel;
|
||||
using System.Data.Entity.Design;
|
||||
|
||||
namespace System.Data.EntityModel.Emitters
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
internal sealed class FixUp
|
||||
{
|
||||
#region Internal Property
|
||||
internal delegate string FixMethod(string line);
|
||||
#endregion
|
||||
|
||||
#region Instance Fields
|
||||
FixUpType m_type;
|
||||
private string _class = null;
|
||||
private string _method = null;
|
||||
private string _property = null;
|
||||
#endregion
|
||||
|
||||
#region static
|
||||
private static readonly FixMethod[] _CSFixMethods = new FixMethod[]
|
||||
{
|
||||
null,
|
||||
new FixMethod(CSMarkOverrideMethodAsSealed),
|
||||
new FixMethod(CSMarkPropertySetAsInternal),
|
||||
new FixMethod(CSMarkClassAsStatic),
|
||||
new FixMethod(CSMarkPropertyGetAsPrivate),
|
||||
new FixMethod(CSMarkPropertyGetAsInternal),
|
||||
new FixMethod(CSMarkPropertyGetAsPublic),
|
||||
new FixMethod(CSMarkPropertySetAsPrivate),
|
||||
new FixMethod(CSMarkPropertySetAsPublic),
|
||||
new FixMethod(CSMarkMethodAsPartial),
|
||||
new FixMethod(CSMarkPropertyGetAsProtected),
|
||||
new FixMethod(CSMarkPropertySetAsProtected)
|
||||
};
|
||||
|
||||
private static readonly FixMethod[] _VBFixMethods = new FixMethod[]
|
||||
{
|
||||
null,
|
||||
new FixMethod(VBMarkOverrideMethodAsSealed),
|
||||
new FixMethod(VBMarkPropertySetAsInternal),
|
||||
null, // VB doesn't support static classes (during CodeGen we added a private ctor to the class)
|
||||
new FixMethod(VBMarkPropertyGetAsPrivate),
|
||||
new FixMethod(VBMarkPropertyGetAsInternal),
|
||||
new FixMethod(VBMarkPropertyGetAsPublic),
|
||||
new FixMethod(VBMarkPropertySetAsPrivate),
|
||||
new FixMethod(VBMarkPropertySetAsPublic),
|
||||
new FixMethod(VBMarkMethodAsPartial),
|
||||
new FixMethod(VBMarkPropertyGetAsProtected),
|
||||
new FixMethod(VBMarkPropertySetAsProtected)
|
||||
};
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="fqName"></param>
|
||||
/// <param name="type"></param>
|
||||
public FixUp(string fqName,FixUpType type)
|
||||
{
|
||||
Type = type;
|
||||
string[] nameParts = Utils.SplitName(fqName);
|
||||
if ( type == FixUpType.MarkClassAsStatic )
|
||||
{
|
||||
Class = nameParts[nameParts.Length-1];
|
||||
}
|
||||
else
|
||||
{
|
||||
Class = nameParts[nameParts.Length-2];
|
||||
string name = nameParts[nameParts.Length-1];
|
||||
switch ( type )
|
||||
{
|
||||
case FixUpType.MarkAbstractMethodAsPartial:
|
||||
case FixUpType.MarkOverrideMethodAsSealed:
|
||||
Method = name;
|
||||
break;
|
||||
case FixUpType.MarkPropertyGetAsPrivate:
|
||||
case FixUpType.MarkPropertyGetAsInternal:
|
||||
case FixUpType.MarkPropertyGetAsPublic:
|
||||
case FixUpType.MarkPropertyGetAsProtected:
|
||||
case FixUpType.MarkPropertySetAsPrivate:
|
||||
case FixUpType.MarkPropertySetAsInternal:
|
||||
case FixUpType.MarkPropertySetAsPublic:
|
||||
case FixUpType.MarkPropertySetAsProtected:
|
||||
Property = name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="language"></param>
|
||||
/// <param name="line"></param>
|
||||
/// <returns></returns>
|
||||
public string Fix(LanguageOption language, string line)
|
||||
{
|
||||
FixMethod method = null;
|
||||
if ( language == LanguageOption.GenerateCSharpCode )
|
||||
{
|
||||
method = _CSFixMethods[(int)Type];
|
||||
}
|
||||
else if ( language == LanguageOption.GenerateVBCode )
|
||||
{
|
||||
method = _VBFixMethods[(int)Type];
|
||||
}
|
||||
|
||||
if ( method != null )
|
||||
{
|
||||
line = method( line );
|
||||
}
|
||||
|
||||
return line;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Public Properties
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
public string Class
|
||||
{
|
||||
get
|
||||
{
|
||||
return _class;
|
||||
}
|
||||
private set
|
||||
{
|
||||
_class = value;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
public string Property
|
||||
{
|
||||
get
|
||||
{
|
||||
return _property;
|
||||
}
|
||||
private set
|
||||
{
|
||||
_property = value;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
public string Method
|
||||
{
|
||||
get
|
||||
{
|
||||
return _method;
|
||||
}
|
||||
private set
|
||||
{
|
||||
_method = value;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
public FixUpType Type
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
private set
|
||||
{
|
||||
m_type = value;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="line"></param>
|
||||
/// <returns></returns>
|
||||
private static string CSMarkMethodAsPartial(string line)
|
||||
{
|
||||
line = ReplaceFirst(line, "public abstract", "partial");
|
||||
return line;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="line"></param>
|
||||
/// <returns></returns>
|
||||
private static string VBMarkMethodAsPartial(string line)
|
||||
{
|
||||
line = ReplaceFirst(line, "Public MustOverride", "Partial Private");
|
||||
line += Environment.NewLine + " End Sub";
|
||||
return line;
|
||||
}
|
||||
|
||||
private static string ReplaceFirst(string line, string str1, string str2)
|
||||
{
|
||||
int idx = line.IndexOf(str1, StringComparison.Ordinal);
|
||||
if (idx >= 0)
|
||||
{
|
||||
line = line.Remove(idx, str1.Length);
|
||||
line = line.Insert(idx, str2);
|
||||
}
|
||||
return line;
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="line"></param>
|
||||
/// <returns></returns>
|
||||
private static string CSMarkOverrideMethodAsSealed(string line)
|
||||
{
|
||||
return InsertBefore(line,"override","sealed");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="line"></param>
|
||||
/// <returns></returns>
|
||||
private static string VBMarkOverrideMethodAsSealed(string line)
|
||||
{
|
||||
return InsertBefore(line, "Overrides", "NotOverridable");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="line"></param>
|
||||
/// <returns></returns>
|
||||
private static string CSMarkPropertySetAsInternal(string line)
|
||||
{
|
||||
return InsertBefore(line,"set","internal");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="line"></param>
|
||||
/// <returns></returns>
|
||||
private static string VBMarkPropertySetAsInternal(string line)
|
||||
{
|
||||
return InsertBefore(line,"Set","Friend");
|
||||
}
|
||||
|
||||
|
||||
private static string CSMarkPropertyGetAsPrivate(string line)
|
||||
{
|
||||
return InsertBefore(line, "get", "private");
|
||||
}
|
||||
|
||||
private static string VBMarkPropertyGetAsPrivate(string line)
|
||||
{
|
||||
return InsertBefore(line, "Get", "Private");
|
||||
}
|
||||
|
||||
|
||||
private static string CSMarkPropertyGetAsInternal(string line)
|
||||
{
|
||||
return InsertBefore(line, "get", "internal");
|
||||
}
|
||||
|
||||
private static string VBMarkPropertyGetAsInternal(string line)
|
||||
{
|
||||
return InsertBefore(line, "Get", "Friend");
|
||||
}
|
||||
|
||||
private static string CSMarkPropertySetAsProtected(string line)
|
||||
{
|
||||
return InsertBefore(line, "set", "protected");
|
||||
}
|
||||
|
||||
private static string VBMarkPropertySetAsProtected(string line)
|
||||
{
|
||||
return InsertBefore(line, "Set", "Protected");
|
||||
}
|
||||
|
||||
private static string CSMarkPropertyGetAsProtected(string line)
|
||||
{
|
||||
return InsertBefore(line, "get", "protected");
|
||||
}
|
||||
|
||||
private static string VBMarkPropertyGetAsProtected(string line)
|
||||
{
|
||||
return InsertBefore(line, "Get", "Protected");
|
||||
}
|
||||
|
||||
private static string CSMarkPropertyGetAsPublic(string line)
|
||||
{
|
||||
return InsertBefore(line, "get", "public");
|
||||
}
|
||||
|
||||
private static string VBMarkPropertyGetAsPublic(string line)
|
||||
{
|
||||
return InsertBefore(line, "Get", "Public");
|
||||
}
|
||||
|
||||
|
||||
private static string CSMarkPropertySetAsPrivate(string line)
|
||||
{
|
||||
return InsertBefore(line, "set", "private");
|
||||
}
|
||||
|
||||
private static string VBMarkPropertySetAsPrivate(string line)
|
||||
{
|
||||
return InsertBefore(line, "Set", "Private");
|
||||
}
|
||||
|
||||
|
||||
private static string CSMarkPropertySetAsPublic(string line)
|
||||
{
|
||||
return InsertBefore(line, "set", "public");
|
||||
}
|
||||
|
||||
private static string VBMarkPropertySetAsPublic(string line)
|
||||
{
|
||||
return InsertBefore(line, "Set", "Public");
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="line"></param>
|
||||
/// <returns></returns>
|
||||
private static string CSMarkClassAsStatic(string line)
|
||||
{
|
||||
if ( IndexOfKeyword(line,"static") >= 0 )
|
||||
return line;
|
||||
|
||||
int insertPoint = IndexOfKeyword(line,"class");
|
||||
if ( insertPoint < 0 )
|
||||
return line;
|
||||
|
||||
// nothing can be between partial and class
|
||||
int partialIndex = IndexOfKeyword(line,"partial");
|
||||
if ( partialIndex >= 0 )
|
||||
insertPoint = partialIndex;
|
||||
|
||||
return line.Insert(insertPoint,"static ");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts one keyword before another one.
|
||||
/// Does nothing if the keyword to be inserted already exists in the line OR if the keyword to insert before doesn't
|
||||
/// </summary>
|
||||
/// <param name="line">line of text to examine</param>
|
||||
/// <param name="searchText">keyword to search for </param>
|
||||
/// <param name="insertText">keyword to be inserted</param>
|
||||
/// <returns>the possibly modified line line</returns>
|
||||
private static string InsertBefore(string line,string searchText,string insertText)
|
||||
{
|
||||
if ( IndexOfKeyword(line,insertText) >= 0 )
|
||||
return line;
|
||||
|
||||
int index = IndexOfKeyword(line,searchText);
|
||||
if ( index < 0 )
|
||||
return line;
|
||||
|
||||
return line.Insert(index,insertText+" ");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds location of a keyword in a line.
|
||||
/// keyword must be at the beginning of the line or preceeded by whitespace AND at the end of the line or followed by whitespace
|
||||
/// </summary>
|
||||
/// <param name="line">line to seach</param>
|
||||
/// <param name="keyword">keyword to search for</param>
|
||||
/// <returns>location of first character of keyword</returns>
|
||||
private static int IndexOfKeyword(string line,string keyword)
|
||||
{
|
||||
int index = line.IndexOf(keyword,StringComparison.Ordinal);
|
||||
if ( index < 0 )
|
||||
return index;
|
||||
|
||||
int indexAfter = index+keyword.Length;
|
||||
if ( (index == 0 || char.IsWhiteSpace(line,index-1)) && (indexAfter == line.Length || char.IsWhiteSpace(line,indexAfter)) )
|
||||
return index;
|
||||
|
||||
return -1;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,41 @@
|
||||
//---------------------------------------------------------------------
|
||||
// <copyright file="FixUpType.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//
|
||||
// @owner jeffreed
|
||||
// @backupOwner srimand
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
namespace System.Data.EntityModel.Emitters
|
||||
{
|
||||
/// <summary>
|
||||
/// Types of fix ups the client code generator can perform on the generated code
|
||||
/// </summary>
|
||||
// these values are used as indexes in the m_fixMethods list.
|
||||
internal enum FixUpType
|
||||
{
|
||||
/// <summary>Mark an override method as final (sealed)</summary>
|
||||
MarkOverrideMethodAsSealed = 1,
|
||||
/// <summary>Mark a property setter as internal</summary>
|
||||
MarkPropertySetAsInternal = 2,
|
||||
/// <summary>Mark a class as static</summary>
|
||||
MarkClassAsStatic = 3,
|
||||
/// <summary>Mark a property getter as private</summary>
|
||||
MarkPropertyGetAsPrivate = 4,
|
||||
/// <summary>Mark a property getter as internal</summary>
|
||||
MarkPropertyGetAsInternal = 5,
|
||||
/// <summary>Mark a property getter as public</summary>
|
||||
MarkPropertyGetAsPublic = 6,
|
||||
/// <summary>Mark a property setter as private</summary>
|
||||
MarkPropertySetAsPrivate = 7,
|
||||
/// <summary>Mark a property setter as public</summary>
|
||||
MarkPropertySetAsPublic = 8,
|
||||
/// <summary>Mark a method as partial</summary>
|
||||
MarkAbstractMethodAsPartial = 9,
|
||||
/// <summary>Mark a property getter as protected</summary>
|
||||
MarkPropertyGetAsProtected = 10,
|
||||
/// <summary>Mark a property setter as protected</summary>
|
||||
MarkPropertySetAsProtected = 11,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
//---------------------------------------------------------------------
|
||||
// <copyright file="MetadataItemEmitter.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//
|
||||
// @owner [....]
|
||||
// @backupOwner [....]
|
||||
//---------------------------------------------------------------------using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Data.Metadata.Edm;
|
||||
using System.Diagnostics;
|
||||
using System.CodeDom;
|
||||
using System.Reflection;
|
||||
|
||||
namespace System.Data.EntityModel.Emitters
|
||||
{
|
||||
internal abstract class MetadataItemEmitter : Emitter
|
||||
{
|
||||
private MetadataItem _item;
|
||||
|
||||
protected MetadataItemEmitter(ClientApiGenerator generator, MetadataItem item)
|
||||
:base(generator)
|
||||
{
|
||||
Debug.Assert(item != null, "item is null");
|
||||
_item = item;
|
||||
}
|
||||
|
||||
protected MetadataItem Item
|
||||
{
|
||||
get { return _item; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Emitter-specific validation here
|
||||
/// </summary>
|
||||
protected abstract void Validate();
|
||||
|
||||
#region Operations for Getting Accessibility
|
||||
|
||||
private const string CodeGenerationValueAccessibilityInternal = "Internal";
|
||||
private const string CodeGenerationValueAccessibilityProtected = "Protected";
|
||||
private const string CodeGenerationValueAccessibilityPublic = "Public";
|
||||
private const string CodeGenerationValueAccessibilityPrivate = "Private";
|
||||
|
||||
#region Protected Block
|
||||
protected static MemberAttributes AccessibilityFromGettersAndSetters(EdmMember property)
|
||||
{
|
||||
MemberAttributes scope = MemberAttributes.Private;
|
||||
|
||||
MemberAttributes getter = GetGetterAccessibility(property);
|
||||
if (IsLeftMoreAccessableThanRight(getter, scope))
|
||||
{
|
||||
scope = getter;
|
||||
}
|
||||
|
||||
MemberAttributes setter = GetSetterAccessibility(property);
|
||||
if (IsLeftMoreAccessableThanRight(setter, scope))
|
||||
{
|
||||
scope = setter;
|
||||
}
|
||||
return scope;
|
||||
}
|
||||
|
||||
protected static MemberAttributes GetGetterAccessibility(EdmMember item)
|
||||
{
|
||||
return GetAccessibilityValue(item, XmlConstants.GetterAccess);
|
||||
}
|
||||
|
||||
protected static MemberAttributes GetSetterAccessibility(EdmMember item)
|
||||
{
|
||||
return GetAccessibilityValue(item, XmlConstants.SetterAccess);
|
||||
}
|
||||
|
||||
protected static MemberAttributes GetFunctionImportAccessibility(EdmFunction item)
|
||||
{
|
||||
return GetAccessibilityValue(item, XmlConstants.MethodAccess);
|
||||
}
|
||||
|
||||
protected static MemberAttributes GetEntitySetPropertyAccessibility(EntitySet item)
|
||||
{
|
||||
return GetAccessibilityValue(item, XmlConstants.GetterAccess);
|
||||
}
|
||||
protected static MemberAttributes GetEntityTypeAccessibility(EntityType item)
|
||||
{
|
||||
return GetAccessibilityValue(item, XmlConstants.TypeAccess);
|
||||
}
|
||||
|
||||
protected static int GetAccessibilityRank(MemberAttributes accessibility)
|
||||
{
|
||||
Debug.Assert(accessibility == MemberAttributes.Private ||
|
||||
accessibility == MemberAttributes.Public ||
|
||||
accessibility == MemberAttributes.Assembly ||
|
||||
accessibility == MemberAttributes.Family,
|
||||
"this method is intended to deal with only single access attributes");
|
||||
switch (accessibility)
|
||||
{
|
||||
case MemberAttributes.Public:
|
||||
return 0;
|
||||
case MemberAttributes.Assembly:
|
||||
return 1;
|
||||
case MemberAttributes.Family:
|
||||
return 2;
|
||||
default:
|
||||
Debug.Assert(accessibility == MemberAttributes.Private, "did a new type get added?");
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
protected static TypeAttributes GetTypeAccessibilityValue(MetadataItem item)
|
||||
{
|
||||
TypeAttributes accessibilty = TypeAttributes.Public;
|
||||
MetadataProperty metadataProperty;
|
||||
if (item.MetadataProperties.TryGetValue(Utils.GetFullyQualifiedCodeGenerationAttributeName(XmlConstants.TypeAccess), false, out metadataProperty))
|
||||
{
|
||||
accessibilty = GetCodeAccessibilityTypeAttribute(metadataProperty.Value.ToString());
|
||||
}
|
||||
return accessibilty;
|
||||
}
|
||||
#endregion Protected
|
||||
|
||||
#region Private Block
|
||||
private static MemberAttributes GetAccessibilityValue(MetadataItem item, string attribute)
|
||||
{
|
||||
MemberAttributes accessibilty = MemberAttributes.Public;
|
||||
MetadataProperty metadataProperty;
|
||||
if (item.MetadataProperties.TryGetValue(Utils.GetFullyQualifiedCodeGenerationAttributeName(attribute), false, out metadataProperty))
|
||||
{
|
||||
accessibilty = GetCodeAccessibilityMemberAttribute(metadataProperty.Value.ToString());
|
||||
}
|
||||
return accessibilty;
|
||||
}
|
||||
|
||||
private static MemberAttributes GetCodeAccessibilityMemberAttribute(string accessibility)
|
||||
{
|
||||
Debug.Assert(accessibility != null, "why does accessibility == null?");
|
||||
|
||||
switch (accessibility)
|
||||
{
|
||||
case CodeGenerationValueAccessibilityInternal:
|
||||
return MemberAttributes.Assembly;
|
||||
case CodeGenerationValueAccessibilityPrivate:
|
||||
return MemberAttributes.Private;
|
||||
case CodeGenerationValueAccessibilityProtected:
|
||||
return MemberAttributes.Family;
|
||||
|
||||
default:
|
||||
Debug.Assert(accessibility == CodeGenerationValueAccessibilityPublic, "found an accessibility other than " + CodeGenerationValueAccessibilityPublic);
|
||||
return MemberAttributes.Public;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given a MemberAttribute, returns a string representation used in CSDL.
|
||||
/// For e.g: MemebrAttribtue.Family is Protected in our csdl, (protected in C#, Family in VB)
|
||||
/// Inverse of the method above (GetCodeAccessibilityMemberAttribute)
|
||||
/// </summary>
|
||||
protected static string GetAccessibilityCsdlStringFromMemberAttribute(MemberAttributes attribute)
|
||||
{
|
||||
switch (attribute)
|
||||
{
|
||||
case MemberAttributes.Assembly:
|
||||
return CodeGenerationValueAccessibilityInternal;
|
||||
case MemberAttributes.Private:
|
||||
return CodeGenerationValueAccessibilityPrivate;
|
||||
case MemberAttributes.Family:
|
||||
return CodeGenerationValueAccessibilityProtected;
|
||||
|
||||
default:
|
||||
Debug.Assert(attribute == MemberAttributes.Public, "found MemberAttribute other than " + CodeGenerationValueAccessibilityPublic);
|
||||
return CodeGenerationValueAccessibilityPublic;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsLeftMoreAccessableThanRight(MemberAttributes left, MemberAttributes right)
|
||||
{
|
||||
return GetAccessibilityRank(left) < GetAccessibilityRank(right);
|
||||
}
|
||||
|
||||
private static TypeAttributes GetCodeAccessibilityTypeAttribute(string accessibility)
|
||||
{
|
||||
Debug.Assert(accessibility != null, "why does accessibility == null?");
|
||||
if (accessibility == CodeGenerationValueAccessibilityInternal || accessibility == CodeGenerationValueAccessibilityProtected)
|
||||
{
|
||||
return TypeAttributes.NotPublic;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Assert(accessibility == CodeGenerationValueAccessibilityPublic, "found an accessibility other than " + CodeGenerationValueAccessibilityPublic);
|
||||
return TypeAttributes.Public;
|
||||
}
|
||||
}
|
||||
#endregion Private
|
||||
|
||||
#endregion Operations for getting Accessibility
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,364 @@
|
||||
//---------------------------------------------------------------------
|
||||
// <copyright file="NavigationPropertyEmitter.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//
|
||||
// @owner [....]
|
||||
// @backupOwner [....]
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.CodeDom;
|
||||
using System.Data;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Entity.Design;
|
||||
using Som=System.Data.EntityModel.SchemaObjectModel;
|
||||
using System.Data.Metadata.Edm;
|
||||
using System.Diagnostics;
|
||||
using System.Data.Entity.Design.SsdlGenerator;
|
||||
using System.Data.Entity.Design.Common;
|
||||
|
||||
|
||||
namespace System.Data.EntityModel.Emitters
|
||||
{
|
||||
/// <summary>
|
||||
/// Summary description for NavigationPropertyEmitter.
|
||||
/// </summary>
|
||||
internal sealed class NavigationPropertyEmitter : PropertyEmitterBase
|
||||
{
|
||||
private const string ValuePropertyName = "Value";
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="generator"></param>
|
||||
/// <param name="navigationProperty"></param>
|
||||
public NavigationPropertyEmitter(ClientApiGenerator generator, NavigationProperty navigationProperty, bool declaringTypeUsesStandardBaseType)
|
||||
: base(generator, navigationProperty, declaringTypeUsesStandardBaseType)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate the navigation property
|
||||
/// </summary>
|
||||
/// <param name="typeDecl">The type to add the property to.</param>
|
||||
protected override void EmitProperty(CodeTypeDeclaration typeDecl)
|
||||
{
|
||||
EmitNavigationProperty(typeDecl);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate the navigation property specified
|
||||
/// </summary>
|
||||
/// <param name="typeDecl">The type to add the property to.</param>
|
||||
private void EmitNavigationProperty( CodeTypeDeclaration typeDecl )
|
||||
{
|
||||
// create a regular property
|
||||
CodeMemberProperty property = EmitNavigationProperty(Item.ToEndMember, false);
|
||||
typeDecl.Members.Add(property);
|
||||
|
||||
if (Item.ToEndMember.RelationshipMultiplicity != RelationshipMultiplicity.Many)
|
||||
{
|
||||
// create a ref property
|
||||
property = EmitNavigationProperty(Item.ToEndMember, true);
|
||||
typeDecl.Members.Add(property);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a navigation property
|
||||
/// </summary>
|
||||
/// <param name="target">the other end</param>
|
||||
/// <param name="referenceProperty">True to emit Reference navigation property</param>
|
||||
/// <returns>the generated property</returns>
|
||||
private CodeMemberProperty EmitNavigationProperty(RelationshipEndMember target, bool referenceProperty)
|
||||
{
|
||||
CodeTypeReference typeRef = GetReturnType(target, referenceProperty);
|
||||
|
||||
// raise the PropertyGenerated event
|
||||
PropertyGeneratedEventArgs eventArgs = new PropertyGeneratedEventArgs(Item,
|
||||
null, // no backing field
|
||||
typeRef);
|
||||
this.Generator.RaisePropertyGeneratedEvent(eventArgs);
|
||||
|
||||
// [System.ComponentModel.Browsable(false)]
|
||||
// public TargetType TargetName
|
||||
// public EntityReference<TargetType> TargetName
|
||||
// or
|
||||
// public EntityCollection<targetType> TargetNames
|
||||
CodeMemberProperty property = new CodeMemberProperty();
|
||||
if (referenceProperty)
|
||||
{
|
||||
AttributeEmitter.AddBrowsableAttribute(property);
|
||||
Generator.AttributeEmitter.EmitGeneratedCodeAttribute(property);
|
||||
}
|
||||
else
|
||||
{
|
||||
Generator.AttributeEmitter.EmitNavigationPropertyAttributes(Generator, target, property, eventArgs.AdditionalAttributes);
|
||||
|
||||
// Only reference navigation properties are currently currently supported with XML serialization
|
||||
// and thus we should use the XmlIgnore and SoapIgnore attributes on other property types.
|
||||
AttributeEmitter.AddIgnoreAttributes(property);
|
||||
}
|
||||
|
||||
AttributeEmitter.AddDataMemberAttribute(property);
|
||||
|
||||
CommentEmitter.EmitSummaryComments(Item, property.Comments);
|
||||
|
||||
property.Name = Item.Name;
|
||||
if (referenceProperty)
|
||||
{
|
||||
property.Name += "Reference";
|
||||
if (IsNameAlreadyAMemberName(Item.DeclaringType, property.Name, Generator.LanguageAppropriateStringComparer))
|
||||
{
|
||||
Generator.AddError(Strings.GeneratedNavigationPropertyNameConflict(Item.Name, Item.DeclaringType.Name, property.Name),
|
||||
ModelBuilderErrorCode.GeneratedNavigationPropertyNameConflict,
|
||||
EdmSchemaErrorSeverity.Error, Item.DeclaringType.FullName, property.Name);
|
||||
}
|
||||
}
|
||||
|
||||
if (eventArgs.ReturnType != null && !eventArgs.ReturnType.Equals(typeRef))
|
||||
{
|
||||
property.Type = eventArgs.ReturnType;
|
||||
}
|
||||
else
|
||||
{
|
||||
property.Type = typeRef;
|
||||
}
|
||||
|
||||
property.Attributes = MemberAttributes.Final;
|
||||
|
||||
CodeMethodInvokeExpression getMethod = EmitGetMethod(target);
|
||||
CodeExpression getReturnExpression;
|
||||
|
||||
property.Attributes |= AccessibilityFromGettersAndSetters(Item);
|
||||
// setup the accessibility of the navigation property setter and getter
|
||||
MemberAttributes propertyAccessibility = property.Attributes & MemberAttributes.AccessMask;
|
||||
PropertyEmitter.AddGetterSetterFixUp(Generator.FixUps, GetFullyQualifiedPropertyName(property.Name),
|
||||
PropertyEmitter.GetGetterAccessibility(Item), propertyAccessibility, true);
|
||||
PropertyEmitter.AddGetterSetterFixUp(Generator.FixUps, GetFullyQualifiedPropertyName(property.Name),
|
||||
PropertyEmitter.GetSetterAccessibility(Item), propertyAccessibility, false);
|
||||
|
||||
if (target.RelationshipMultiplicity != RelationshipMultiplicity.Many)
|
||||
{
|
||||
|
||||
// insert user-supplied Set code here, before the assignment
|
||||
//
|
||||
List<CodeStatement> additionalSetStatements = eventArgs.AdditionalSetStatements;
|
||||
if (additionalSetStatements != null && additionalSetStatements.Count > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
property.SetStatements.AddRange(additionalSetStatements.ToArray());
|
||||
}
|
||||
catch (ArgumentNullException ex)
|
||||
{
|
||||
Generator.AddError(Strings.InvalidSetStatementSuppliedForProperty(Item.Name),
|
||||
ModelBuilderErrorCode.InvalidSetStatementSuppliedForProperty,
|
||||
EdmSchemaErrorSeverity.Error,
|
||||
ex);
|
||||
}
|
||||
}
|
||||
|
||||
CodeExpression valueRef = new CodePropertySetValueReferenceExpression();
|
||||
if(typeRef != eventArgs.ReturnType)
|
||||
{
|
||||
// we need to cast to the actual type
|
||||
valueRef = new CodeCastExpression(typeRef, valueRef);
|
||||
}
|
||||
|
||||
if (referenceProperty)
|
||||
{
|
||||
// get
|
||||
// return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<TTargetEntity>("CSpaceQualifiedRelationshipName", "TargetRoleName");
|
||||
getReturnExpression = getMethod;
|
||||
|
||||
// set
|
||||
// if (value != null)
|
||||
// {
|
||||
// ((IEntityWithRelationships)this).RelationshipManager.InitializeRelatedReference<TTargetEntity>"CSpaceQualifiedRelationshipName", "TargetRoleName", value);
|
||||
// }
|
||||
|
||||
CodeMethodReferenceExpression initReferenceMethod = new CodeMethodReferenceExpression();
|
||||
initReferenceMethod.MethodName = "InitializeRelatedReference";
|
||||
|
||||
initReferenceMethod.TypeArguments.Add(Generator.GetLeastPossibleQualifiedTypeReference(GetEntityType(target)));
|
||||
initReferenceMethod.TargetObject = new CodePropertyReferenceExpression(
|
||||
new CodeCastExpression(TypeReference.IEntityWithRelationshipsTypeBaseClass, ThisRef),
|
||||
"RelationshipManager");
|
||||
|
||||
// relationships aren't backed by types so we won't map the namespace
|
||||
// or we can't find the relationship again later
|
||||
string cspaceNamespaceNameQualifiedRelationshipName = target.DeclaringType.FullName;
|
||||
|
||||
property.SetStatements.Add(
|
||||
new CodeConditionStatement(
|
||||
EmitExpressionDoesNotEqualNull(valueRef),
|
||||
new CodeExpressionStatement(
|
||||
new CodeMethodInvokeExpression(
|
||||
initReferenceMethod, new CodeExpression[] {
|
||||
new CodePrimitiveExpression(cspaceNamespaceNameQualifiedRelationshipName), new CodePrimitiveExpression(target.Name), valueRef}))));
|
||||
}
|
||||
else
|
||||
{
|
||||
CodePropertyReferenceExpression valueProperty = new CodePropertyReferenceExpression(getMethod, ValuePropertyName);
|
||||
|
||||
// get
|
||||
// return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<TTargetEntity>("CSpaceQualifiedRelationshipName", "TargetRoleName").Value;
|
||||
getReturnExpression = valueProperty;
|
||||
|
||||
// set
|
||||
// ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<TTargetEntity>("CSpaceQualifiedRelationshipName", "TargetRoleName").Value = value;
|
||||
property.SetStatements.Add(
|
||||
new CodeAssignStatement(valueProperty, valueRef));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// get
|
||||
// return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedCollection<TTargetEntity>("CSpaceQualifiedRelationshipName", "TargetRoleName");
|
||||
getReturnExpression = getMethod;
|
||||
|
||||
// set
|
||||
// if (value != null)
|
||||
// {
|
||||
// ((IEntityWithRelationships)this).RelationshipManager.InitializeRelatedCollection<TTargetEntity>"CSpaceQualifiedRelationshipName", "TargetRoleName", value);
|
||||
// }
|
||||
CodeExpression valueRef = new CodePropertySetValueReferenceExpression();
|
||||
|
||||
CodeMethodReferenceExpression initCollectionMethod = new CodeMethodReferenceExpression();
|
||||
initCollectionMethod.MethodName = "InitializeRelatedCollection";
|
||||
|
||||
initCollectionMethod.TypeArguments.Add(Generator.GetLeastPossibleQualifiedTypeReference(GetEntityType(target)));
|
||||
initCollectionMethod.TargetObject = new CodePropertyReferenceExpression(
|
||||
new CodeCastExpression(TypeReference.IEntityWithRelationshipsTypeBaseClass, ThisRef),
|
||||
"RelationshipManager");
|
||||
|
||||
// relationships aren't backed by types so we won't map the namespace
|
||||
// or we can't find the relationship again later
|
||||
string cspaceNamespaceNameQualifiedRelationshipName = target.DeclaringType.FullName;
|
||||
|
||||
property.SetStatements.Add(
|
||||
new CodeConditionStatement(
|
||||
EmitExpressionDoesNotEqualNull(valueRef),
|
||||
new CodeExpressionStatement(
|
||||
new CodeMethodInvokeExpression(
|
||||
initCollectionMethod, new CodeExpression[] {
|
||||
new CodePrimitiveExpression(cspaceNamespaceNameQualifiedRelationshipName), new CodePrimitiveExpression(target.Name), valueRef}))));
|
||||
|
||||
}
|
||||
|
||||
// if additional Get statements were specified by the event subscriber, insert them now
|
||||
//
|
||||
List<CodeStatement> additionalGetStatements = eventArgs.AdditionalGetStatements;
|
||||
if (additionalGetStatements != null && additionalGetStatements.Count > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
property.GetStatements.AddRange(additionalGetStatements.ToArray());
|
||||
}
|
||||
catch (ArgumentNullException ex)
|
||||
{
|
||||
Generator.AddError(Strings.InvalidGetStatementSuppliedForProperty(Item.Name),
|
||||
ModelBuilderErrorCode.InvalidGetStatementSuppliedForProperty,
|
||||
EdmSchemaErrorSeverity.Error,
|
||||
ex);
|
||||
}
|
||||
}
|
||||
|
||||
property.GetStatements.Add(new CodeMethodReturnStatement(getReturnExpression));
|
||||
|
||||
return property;
|
||||
}
|
||||
|
||||
internal static bool IsNameAlreadyAMemberName(StructuralType type, string generatedPropertyName, StringComparison comparison)
|
||||
{
|
||||
foreach (EdmMember member in type.Members)
|
||||
{
|
||||
if (member.DeclaringType == type &&
|
||||
member.Name.Equals(generatedPropertyName, comparison))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private string GetFullyQualifiedPropertyName(string propertyName)
|
||||
{
|
||||
return Item.DeclaringType.FullName + "." + propertyName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gives the SchemaElement back cast to the most
|
||||
/// appropriate type
|
||||
/// </summary>
|
||||
private new NavigationProperty Item
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.Item as NavigationProperty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the return type for the get method, given the target end
|
||||
/// </summary>
|
||||
/// <param name="target"></param>
|
||||
/// <param name="referenceMethod">true if the is the return type for a reference property</param>
|
||||
/// <returns>the return type for a target</returns>
|
||||
private CodeTypeReference GetReturnType(RelationshipEndMember target, bool referenceMethod)
|
||||
{
|
||||
CodeTypeReference returnType = Generator.GetLeastPossibleQualifiedTypeReference(GetEntityType(target));
|
||||
if (referenceMethod)
|
||||
{
|
||||
returnType = TypeReference.AdoFrameworkGenericDataClass("EntityReference", returnType);
|
||||
}
|
||||
else if (target.RelationshipMultiplicity == RelationshipMultiplicity.Many)
|
||||
{
|
||||
returnType = TypeReference.AdoFrameworkGenericDataClass("EntityCollection", returnType);
|
||||
}
|
||||
|
||||
return returnType;
|
||||
}
|
||||
|
||||
|
||||
private static EntityTypeBase GetEntityType(RelationshipEndMember endMember)
|
||||
{
|
||||
Debug.Assert(endMember.TypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.RefType, "not a reference type");
|
||||
EntityTypeBase type = ((RefType)endMember.TypeUsage.EdmType).ElementType;
|
||||
return type;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Emit the GetRelatedCollection or GetRelatedReference methods
|
||||
/// </summary>
|
||||
/// <param name="target">Target end of the relationship</param>
|
||||
/// <returns>Expression to invoke the appropriate method</returns>
|
||||
private CodeMethodInvokeExpression EmitGetMethod(RelationshipEndMember target)
|
||||
{
|
||||
// ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<TargetType>("CSpaceQualifiedRelationshipName", "TargetRoleName");
|
||||
// or
|
||||
// ((IEntityWithRelationships)this).RelationshipManager.GetRelatedCollection<TargetType>("CSpaceQualifiedRelationshipName", "TargetRoleName");
|
||||
|
||||
CodeMethodReferenceExpression getMethod = new CodeMethodReferenceExpression();
|
||||
if (target.RelationshipMultiplicity != RelationshipMultiplicity.Many)
|
||||
getMethod.MethodName = "GetRelatedReference";
|
||||
else
|
||||
getMethod.MethodName = "GetRelatedCollection";
|
||||
|
||||
getMethod.TypeArguments.Add(Generator.GetLeastPossibleQualifiedTypeReference(GetEntityType(target)));
|
||||
getMethod.TargetObject = new CodePropertyReferenceExpression(
|
||||
new CodeCastExpression(TypeReference.IEntityWithRelationshipsTypeBaseClass, ThisRef),
|
||||
"RelationshipManager");
|
||||
|
||||
// relationships aren't backed by types so we won't map the namespace
|
||||
// or we can't find the relationship again later
|
||||
string cspaceNamespaceNameQualifiedRelationshipName = target.DeclaringType.FullName;
|
||||
return new CodeMethodInvokeExpression(
|
||||
getMethod, new CodeExpression[] { new CodePrimitiveExpression(cspaceNamespaceNameQualifiedRelationshipName), new CodePrimitiveExpression(target.Name)});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
//---------------------------------------------------------------------
|
||||
// <copyright file="PrivateMemberPrefixId.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//
|
||||
// @owner jeffreed
|
||||
// @backupOwner srimand
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
|
||||
|
||||
namespace System.Data.EntityModel.Emitters
|
||||
{
|
||||
internal enum PrivateMemberPrefixId
|
||||
{
|
||||
Field,
|
||||
IntializeMethod,
|
||||
PropertyInfoProperty,
|
||||
PropertyInfoField,
|
||||
// add additional members here
|
||||
Count
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,105 @@
|
||||
//---------------------------------------------------------------------
|
||||
// <copyright file="PropertyEmitterBase.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//
|
||||
// @owner [....]
|
||||
// @backupOwner [....]
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.CodeDom;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Metadata.Edm;
|
||||
using System.Diagnostics;
|
||||
using System.Data.Entity.Design.SsdlGenerator;
|
||||
using System.Data.Entity.Design.Common;
|
||||
|
||||
namespace System.Data.EntityModel.Emitters
|
||||
{
|
||||
internal abstract class PropertyEmitterBase : MetadataItemEmitter
|
||||
{
|
||||
private bool _declaringTypeUsesStandardBaseType;
|
||||
protected PropertyEmitterBase(ClientApiGenerator generator, MetadataItem item, bool declaringTypeUsesStandardBaseType)
|
||||
:base(generator, item)
|
||||
{
|
||||
Debug.Assert(item != null, "item is null");
|
||||
_declaringTypeUsesStandardBaseType = declaringTypeUsesStandardBaseType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is where the derived classes supply their emit logic.
|
||||
/// </summary>
|
||||
/// <param name="typeDecl">The CodeDom representation of the type that the property is being added to.</param>
|
||||
protected abstract void EmitProperty(CodeTypeDeclaration typeDecl);
|
||||
|
||||
/// <summary>
|
||||
/// Validation logic specific to property emitters
|
||||
/// </summary>
|
||||
protected override void Validate()
|
||||
{
|
||||
VerifyGetterAndSetterAccessibilityCompatability();
|
||||
Generator.VerifyLanguageCaseSensitiveCompatibilityForProperty(Item as EdmMember);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The compiler ensures accessibility on a Setter/Getter is more restrictive than on the Property.
|
||||
/// However accessibility modifiers are not well ordered. Internal and Protected don't go well together
|
||||
/// because neither is more restrictive than others.
|
||||
/// </summary>
|
||||
private void VerifyGetterAndSetterAccessibilityCompatability()
|
||||
{
|
||||
if (PropertyEmitter.GetGetterAccessibility(Item) == MemberAttributes.Assembly
|
||||
&& PropertyEmitter.GetSetterAccessibility(Item) == MemberAttributes.Family)
|
||||
{
|
||||
Generator.AddError(System.Data.Entity.Design.Strings.GeneratedPropertyAccessibilityConflict(Item.Name, "Internal", "Protected"),
|
||||
ModelBuilderErrorCode.GeneratedPropertyAccessibilityConflict,
|
||||
EdmSchemaErrorSeverity.Error, Item.DeclaringType.FullName, Item.Name);
|
||||
}
|
||||
else if (PropertyEmitter.GetGetterAccessibility(Item) == MemberAttributes.Family
|
||||
&& PropertyEmitter.GetSetterAccessibility(Item) == MemberAttributes.Assembly)
|
||||
{
|
||||
Generator.AddError(System.Data.Entity.Design.Strings.GeneratedPropertyAccessibilityConflict(Item.Name, "Protected", "Internal"),
|
||||
ModelBuilderErrorCode.GeneratedPropertyAccessibilityConflict,
|
||||
EdmSchemaErrorSeverity.Error, Item.DeclaringType.FullName, Item.Name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Main method for Emitting property code.
|
||||
/// </summary>
|
||||
/// <param name="typeDecl">The CodeDom representation of the type that the property is being added to.</param>
|
||||
public void Emit(CodeTypeDeclaration typeDecl)
|
||||
{
|
||||
Validate();
|
||||
EmitProperty(typeDecl);
|
||||
}
|
||||
|
||||
protected bool AncestorClassDefinesName(string name)
|
||||
{
|
||||
if (_declaringTypeUsesStandardBaseType && Utils.DoesTypeReserveMemberName(Item.DeclaringType, name, Generator.LanguageAppropriateStringComparer))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
StructuralType baseType = Item.DeclaringType.BaseType as StructuralType;
|
||||
if (baseType != null && baseType.Members.Contains(name))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public new EdmMember Item
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.Item as EdmMember;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
//---------------------------------------------------------------------
|
||||
// <copyright file="SchemaTypeEmitter.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//
|
||||
// @owner [....]
|
||||
// @backupOwner [....]
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.CodeDom;
|
||||
using System.Data.EntityModel.SchemaObjectModel;
|
||||
using Som = System.Data.EntityModel.SchemaObjectModel;
|
||||
using System.Data.Metadata.Edm;
|
||||
using System.Reflection;
|
||||
using System.Diagnostics;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Entity.Design;
|
||||
using System.Data.Entity.Design.SsdlGenerator;
|
||||
|
||||
|
||||
namespace System.Data.EntityModel.Emitters
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
internal abstract class SchemaTypeEmitter : MetadataItemEmitter
|
||||
{
|
||||
#region Public Methods
|
||||
public abstract CodeTypeDeclarationCollection EmitApiClass();
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="generator"></param>
|
||||
/// <param name="schemaType"></param>
|
||||
protected SchemaTypeEmitter(ClientApiGenerator generator, MetadataItem item)
|
||||
: base(generator, item)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="typeDecl"></param>
|
||||
protected virtual void EmitTypeAttributes( CodeTypeDeclaration typeDecl )
|
||||
{
|
||||
Generator.AttributeEmitter.EmitTypeAttributes( this, typeDecl );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Emitter-specific validation: for SchemaTypeEmitter-derived classes, we
|
||||
/// check the EdmItemCollection for other entities that have the same name
|
||||
/// but differ in case
|
||||
/// </summary>
|
||||
protected override void Validate()
|
||||
{
|
||||
Generator.VerifyLanguageCaseSensitiveCompatibilityForType(Item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add attributes to a type's CustomAttributes collection
|
||||
/// </summary>
|
||||
/// <param name="itemName">The name of the type</param>
|
||||
/// <param name="typeDecl">The type to annotate</param>
|
||||
/// <param name="additionalAttributes">The additional attributes</param>
|
||||
protected void EmitTypeAttributes(string itemName, CodeTypeDeclaration typeDecl,
|
||||
List<CodeAttributeDeclaration> additionalAttributes)
|
||||
{
|
||||
if (additionalAttributes != null && additionalAttributes.Count > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
typeDecl.CustomAttributes.AddRange(additionalAttributes.ToArray());
|
||||
}
|
||||
catch (ArgumentNullException e)
|
||||
{
|
||||
Generator.AddError(Strings.InvalidAttributeSuppliedForType(itemName),
|
||||
ModelBuilderErrorCode.InvalidAttributeSuppliedForType,
|
||||
EdmSchemaErrorSeverity.Error,
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
EmitTypeAttributes(typeDecl);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add interfaces to the type's list of BaseTypes
|
||||
/// </summary>
|
||||
/// <param name="itemName">The name of the type</param>
|
||||
/// <param name="typeDecl">The type whose list of base types needs to be extended</param>
|
||||
/// <param name="additionalInterfaces">The interfaces to add to the list of base types</param>
|
||||
protected void AddInterfaces(string itemName,
|
||||
CodeTypeDeclaration typeDecl,
|
||||
List<Type> additionalInterfaces)
|
||||
{
|
||||
if (additionalInterfaces != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (Type interfaceType in additionalInterfaces)
|
||||
{
|
||||
typeDecl.BaseTypes.Add(new CodeTypeReference(interfaceType));
|
||||
}
|
||||
}
|
||||
catch (ArgumentNullException e)
|
||||
{
|
||||
Generator.AddError(Strings.InvalidInterfaceSuppliedForType(itemName),
|
||||
ModelBuilderErrorCode.InvalidInterfaceSuppliedForType,
|
||||
EdmSchemaErrorSeverity.Error,
|
||||
e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add interfaces to the type's list of BaseTypes
|
||||
/// </summary>
|
||||
/// <param name="itemName">The name of the type</param>
|
||||
/// <param name="typeDecl">The type to which members need to be added</param>
|
||||
/// <param name="additionalMembers">The members to add</param>
|
||||
protected void AddMembers(string itemName, CodeTypeDeclaration typeDecl,
|
||||
List<CodeTypeMember> additionalMembers)
|
||||
{
|
||||
if (additionalMembers != null && additionalMembers.Count > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
typeDecl.Members.AddRange(additionalMembers.ToArray());
|
||||
}
|
||||
catch (ArgumentNullException e)
|
||||
{
|
||||
Generator.AddError(Strings.InvalidMemberSuppliedForType(itemName),
|
||||
ModelBuilderErrorCode.InvalidMemberSuppliedForType,
|
||||
EdmSchemaErrorSeverity.Error,
|
||||
e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the element that code is being emitted for.
|
||||
/// </summary>
|
||||
internal new GlobalItem Item
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.Item as GlobalItem;
|
||||
}
|
||||
}
|
||||
|
||||
internal void SetTypeVisibility(CodeTypeDeclaration typeDecl)
|
||||
{
|
||||
typeDecl.TypeAttributes &= ~System.Reflection.TypeAttributes.VisibilityMask;
|
||||
typeDecl.TypeAttributes |= GetTypeAccessibilityValue(Item);
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,312 @@
|
||||
//---------------------------------------------------------------------
|
||||
// <copyright file="StructuredTypeEmitter.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//
|
||||
// @owner [....]
|
||||
// @backupOwner [....]
|
||||
//---------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.CodeDom;
|
||||
using System.Data;
|
||||
using System.Data.EntityModel.SchemaObjectModel;
|
||||
using Som = System.Data.EntityModel.SchemaObjectModel;
|
||||
using System.Data.Entity.Design;
|
||||
using System.Data.Metadata.Edm;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using System.Data.Objects.DataClasses;
|
||||
using System.Data.Entity.Design.Common;
|
||||
using System.Data.Entity.Design.SsdlGenerator;
|
||||
|
||||
|
||||
namespace System.Data.EntityModel.Emitters
|
||||
{
|
||||
/// <summary>
|
||||
/// Summary description for StructuredTypeEmitter.
|
||||
/// </summary>
|
||||
internal abstract class StructuredTypeEmitter : SchemaTypeEmitter
|
||||
{
|
||||
#region Public Methods
|
||||
private bool _usingStandardBaseClass = true;
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override CodeTypeDeclarationCollection EmitApiClass()
|
||||
{
|
||||
Validate(); // emitter-specific validation
|
||||
|
||||
CodeTypeReference baseType = this.GetBaseType();
|
||||
|
||||
// raise the TypeGenerated event
|
||||
TypeGeneratedEventArgs eventArgs = new TypeGeneratedEventArgs(Item, baseType);
|
||||
this.Generator.RaiseTypeGeneratedEvent(eventArgs);
|
||||
|
||||
// public [abstract] partial class ClassName
|
||||
CodeTypeDeclaration typeDecl = new CodeTypeDeclaration(Item.Name);
|
||||
typeDecl.IsPartial = true;
|
||||
typeDecl.TypeAttributes = System.Reflection.TypeAttributes.Class;
|
||||
if (Item.Abstract)
|
||||
{
|
||||
typeDecl.TypeAttributes |= System.Reflection.TypeAttributes.Abstract;
|
||||
}
|
||||
|
||||
SetTypeVisibility(typeDecl);
|
||||
|
||||
EmitTypeAttributes(Item.Name, typeDecl, eventArgs.AdditionalAttributes);
|
||||
|
||||
// : baseclass
|
||||
AssignBaseType(typeDecl, baseType, eventArgs.BaseType);
|
||||
|
||||
AddInterfaces(Item.Name, typeDecl, eventArgs.AdditionalInterfaces);
|
||||
|
||||
CommentEmitter.EmitSummaryComments(Item, typeDecl.Comments);
|
||||
|
||||
// Since abstract types cannot be instantiated, skip the factory method for abstract types
|
||||
if ( (typeDecl.TypeAttributes & System.Reflection.TypeAttributes.Abstract) == 0)
|
||||
EmitFactoryMethod(typeDecl);
|
||||
|
||||
EmitProperties(typeDecl);
|
||||
|
||||
// additional members, if provided by the event subscriber
|
||||
this.AddMembers(Item.Name, typeDecl, eventArgs.AdditionalMembers);
|
||||
|
||||
CodeTypeDeclarationCollection typeDecls = new CodeTypeDeclarationCollection();
|
||||
typeDecls.Add(typeDecl);
|
||||
return typeDecls;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected virtual CodeTypeReference GetBaseType()
|
||||
{
|
||||
if (Item.BaseType == null)
|
||||
return null;
|
||||
|
||||
return Generator.GetLeastPossibleQualifiedTypeReference(Item.BaseType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="generator"></param>
|
||||
/// <param name="structuredType"></param>
|
||||
protected StructuredTypeEmitter(ClientApiGenerator generator, StructuralType structuralType)
|
||||
: base(generator, structuralType)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="typeDecl"></param>
|
||||
protected override void EmitTypeAttributes(CodeTypeDeclaration typeDecl)
|
||||
{
|
||||
Generator.AttributeEmitter.EmitTypeAttributes(this, typeDecl);
|
||||
base.EmitTypeAttributes(typeDecl);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="typeDecl"></param>
|
||||
protected virtual void EmitProperties(CodeTypeDeclaration typeDecl)
|
||||
{
|
||||
|
||||
foreach (EdmProperty property in Item.GetDeclaredOnlyMembers<EdmProperty>())
|
||||
{
|
||||
PropertyEmitter propertyEmitter = new PropertyEmitter(Generator, property, _usingStandardBaseClass);
|
||||
propertyEmitter.Emit(typeDecl);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract ReadOnlyMetadataCollection<EdmProperty> GetProperties();
|
||||
|
||||
/// <summary>
|
||||
/// Emit static factory method which creates an instance of the class and initializes
|
||||
/// non-nullable properties (taken as arguments)
|
||||
/// </summary>
|
||||
/// <param name="typeDecl"></param>
|
||||
protected virtual void EmitFactoryMethod(CodeTypeDeclaration typeDecl)
|
||||
{
|
||||
|
||||
|
||||
// build list of non-nullable properties
|
||||
ReadOnlyMetadataCollection<EdmProperty> properties = GetProperties();
|
||||
List<EdmProperty> parameters = new List<EdmProperty>(properties.Count);
|
||||
foreach (EdmProperty property in properties)
|
||||
{
|
||||
bool include = IncludeFieldInFactoryMethod(property);
|
||||
if (include)
|
||||
{
|
||||
parameters.Add(property);
|
||||
}
|
||||
}
|
||||
|
||||
// if there are no parameters, we don't emit anything (1 is for the null element)
|
||||
// nor do we emit everything if this is the Ref propertied ctor and the parameter list is the same as the many parametered ctor
|
||||
if (parameters.Count < 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CodeMemberMethod method = new CodeMemberMethod();
|
||||
Generator.AttributeEmitter.EmitGeneratedCodeAttribute(method);
|
||||
|
||||
CodeTypeReference typeRef = TypeReference.FromString(Item.Name);
|
||||
UniqueIdentifierService uniqueIdentifierService = new UniqueIdentifierService(Generator.IsLanguageCaseSensitive, name => Utils.FixParameterName(name));
|
||||
string instanceName = uniqueIdentifierService.AdjustIdentifier(Item.Name);
|
||||
|
||||
// public static Class CreateClass(...)
|
||||
method.Attributes = MemberAttributes.Static|MemberAttributes.Public;
|
||||
method.Name = "Create" + Item.Name;
|
||||
if (NavigationPropertyEmitter.IsNameAlreadyAMemberName(Item, method.Name, Generator.LanguageAppropriateStringComparer))
|
||||
{
|
||||
Generator.AddError(Strings.GeneratedFactoryMethodNameConflict(method.Name, Item.Name),
|
||||
ModelBuilderErrorCode.GeneratedFactoryMethodNameConflict,
|
||||
EdmSchemaErrorSeverity.Error, Item.FullName);
|
||||
}
|
||||
|
||||
method.ReturnType = typeRef;
|
||||
|
||||
// output method summary comments
|
||||
CommentEmitter.EmitSummaryComments(Strings.FactoryMethodSummaryComment(Item.Name), method.Comments);
|
||||
|
||||
|
||||
// Class class = new Class();
|
||||
CodeVariableDeclarationStatement createNewInstance = new CodeVariableDeclarationStatement(
|
||||
typeRef, instanceName, new CodeObjectCreateExpression(typeRef));
|
||||
method.Statements.Add(createNewInstance);
|
||||
CodeVariableReferenceExpression instanceRef = new CodeVariableReferenceExpression(instanceName);
|
||||
|
||||
// iterate over the properties figuring out which need included in the factory method
|
||||
foreach (EdmProperty property in parameters)
|
||||
{
|
||||
// CreateClass( ... , propType propName ...)
|
||||
PropertyEmitter propertyEmitter = new PropertyEmitter(Generator, property, UsingStandardBaseClass);
|
||||
CodeTypeReference propertyTypeReference = propertyEmitter.PropertyType;
|
||||
String parameterName = uniqueIdentifierService.AdjustIdentifier(propertyEmitter.PropertyName);
|
||||
CodeParameterDeclarationExpression paramDecl = new CodeParameterDeclarationExpression(
|
||||
propertyTypeReference, parameterName);
|
||||
CodeArgumentReferenceExpression paramRef = new CodeArgumentReferenceExpression(paramDecl.Name);
|
||||
method.Parameters.Add(paramDecl);
|
||||
|
||||
// add comment describing the parameter
|
||||
CommentEmitter.EmitParamComments(paramDecl, Strings.FactoryParamCommentGeneral(propertyEmitter.PropertyName), method.Comments);
|
||||
|
||||
CodeExpression newPropertyValue;
|
||||
if (MetadataUtil.IsComplexType(propertyEmitter.Item.TypeUsage.EdmType))
|
||||
{
|
||||
List<CodeExpression> complexVerifyParameters = new List<CodeExpression>();
|
||||
complexVerifyParameters.Add(paramRef);
|
||||
complexVerifyParameters.Add(new CodePrimitiveExpression(propertyEmitter.PropertyName));
|
||||
|
||||
newPropertyValue =
|
||||
new CodeMethodInvokeExpression(
|
||||
PropertyEmitter.CreateEdmStructuralObjectRef(TypeReference),
|
||||
Utils.VerifyComplexObjectIsNotNullName,
|
||||
complexVerifyParameters.ToArray());
|
||||
}
|
||||
else
|
||||
{
|
||||
newPropertyValue = paramRef;
|
||||
}
|
||||
|
||||
// Scalar property:
|
||||
// Property = param;
|
||||
// Complex property:
|
||||
// Property = StructuralObject.VerifyComplexObjectIsNotNull(param, propertyName);
|
||||
|
||||
method.Statements.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(instanceRef, propertyEmitter.PropertyName), newPropertyValue));
|
||||
}
|
||||
|
||||
// return class;
|
||||
method.Statements.Add(new CodeMethodReturnStatement(instanceRef));
|
||||
|
||||
// actually add the method to the class
|
||||
typeDecl.Members.Add(method);
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Properties
|
||||
|
||||
internal new StructuralType Item
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.Item as StructuralType;
|
||||
}
|
||||
}
|
||||
|
||||
protected bool UsingStandardBaseClass
|
||||
{
|
||||
get { return _usingStandardBaseClass; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="property"></param>
|
||||
/// <returns></returns>
|
||||
private bool IncludeFieldInFactoryMethod(EdmProperty property)
|
||||
{
|
||||
if (property.Nullable)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (PropertyEmitter.HasDefault(property))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((PropertyEmitter.GetGetterAccessibility(property) != MemberAttributes.Public &&
|
||||
PropertyEmitter.GetSetterAccessibility(property) != MemberAttributes.Public) ||
|
||||
// declared in a sub type, but not setter accessbile from this type
|
||||
(Item != property.DeclaringType && PropertyEmitter.GetSetterAccessibility(property) == MemberAttributes.Private)
|
||||
)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void AssignBaseType(CodeTypeDeclaration typeDecl,
|
||||
CodeTypeReference baseType,
|
||||
CodeTypeReference eventReturnedBaseType)
|
||||
{
|
||||
if (eventReturnedBaseType != null && !eventReturnedBaseType.Equals(baseType))
|
||||
{
|
||||
_usingStandardBaseClass = false;
|
||||
typeDecl.BaseTypes.Add(eventReturnedBaseType);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (baseType != null)
|
||||
{
|
||||
typeDecl.BaseTypes.Add(baseType);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user