Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataWeb / Design / system / Data / EntityModel / Emitters / ClientApiGenerator.cs / 1625574 / ClientApiGenerator.cs
//----------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Generic;
using System.Data.EntityModel.Emitters;
using System.Data.Metadata.Edm;
using System.Data.Services.Design;
using System.Diagnostics;
using System.IO;
using System.Linq;
namespace System.Data.Metadata.Edm
{
internal static partial class Helper
{
internal static bool IsCollectionType(GlobalItem item)
{
return (BuiltInTypeKind.CollectionType == item.BuiltInTypeKind);
}
internal static bool IsComplexType(EdmType type)
{
return (BuiltInTypeKind.ComplexType == type.BuiltInTypeKind);
}
internal static bool IsEntitySet(EntitySetBase entitySetBase)
{
return BuiltInTypeKind.EntitySet == entitySetBase.BuiltInTypeKind;
}
internal static bool IsPrimitiveType(EdmType type)
{
return (BuiltInTypeKind.PrimitiveType == type.BuiltInTypeKind);
}
}
internal static class TypeSemantics
{
internal static bool IsComplexType(TypeUsage type)
{
return Helper.IsComplexType(type.EdmType);
}
}
internal static class EdmProviderManifest
{
// System Facet Info
///
/// Name of the MaxLength Facet
///
internal const string MaxLengthFacetName = "MaxLength";
///
/// Name of the Unicode Facet
///
internal const string UnicodeFacetName = "Unicode";
///
/// Name of the FixedLength Facet
///
internal const string FixedLengthFacetName = "FixedLength";
///
/// Name of the DateTimeKind Facet
///
internal const string DateTimeKindFacetName = "DateTimeKind";
///
/// Name of the PreserveSeconds Facet
///
internal const string PreserveSecondsFacetName = "PreserveSeconds";
///
/// Name of the Precision Facet
///
internal const string PrecisionFacetName = "Precision";
///
/// Name of the Scale Facet
///
internal const string ScaleFacetName = "Scale";
///
/// Name of the Nullable Facet
///
internal const string NullableFacetName = "Nullable";
///
/// Name of the DefaultValue Facet
///
internal const string DefaultValueFacetName = "DefaultValue";
/////
///// Name of the DefaultType metadata property
/////
//internal const string DefaultTypeMetadataPropertyName = "DefaultType";
///
/// Name of the Collation Facet
///
internal const string CollationFacetName = "Collation";
}
internal static class TypeSystem
{
private static readonly System.Reflection.MethodInfo s_getDefaultMethod = typeof(TypeSystem).GetMethod("GetDefault", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
private static T GetDefault() { return default(T); }
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining | System.Runtime.CompilerServices.MethodImplOptions.NoOptimization)]
internal static object GetDefaultValue(Type type)
{
// null is always the default for non value types and Nullable<>
if (!type.IsValueType ||
(type.IsGenericType &&
typeof(Nullable<>) == type.GetGenericTypeDefinition()))
{
return null;
}
System.Reflection.MethodInfo getDefaultMethod = s_getDefaultMethod.MakeGenericMethod(type);
object defaultValue = getDefaultMethod.Invoke(null, new object[] { });
return defaultValue;
}
}
internal static class Schema
{
public const string CodeGenerationSchemaNamespace = "http://schemas.microsoft.com/ado/2006/04/codegeneration";
}
}
namespace System.Data.EntityModel
{
///
/// Summary description for ClientApiGenerator.
///
internal sealed class ClientApiGenerator : IDisposable
{
#region Instance Fields
private CodeCompileUnit _compileUnit;
private bool _isLanguageCaseSensitive = true;
private EdmItemCollection _edmItemCollection;
private FixUpCollection _fixUps;
private AttributeEmitter _attributeEmitter;
private EntityClassGenerator _generator;
private List _errors;
private TypeReference _typeReference = new TypeReference();
private string _sourceEdmNamespaceName;
private string _defaultContainerNamespace;
private string _namespacePrefix;
private Dictionary _namespaceMap;
private EventHandler _onTypeGenerated;
private EventHandler _onPropertyGenerated;
#endregion
#region Public Methods
public ClientApiGenerator(object sourceSchema, EdmItemCollection edmItemCollection, EntityClassGenerator generator, List errors, string namespacePrefix)
{
Debug.Assert(edmItemCollection != null, "edmItemCollection is null");
Debug.Assert(generator != null, "generator is null");
Debug.Assert(errors != null, "errors is null");
_edmItemCollection = edmItemCollection;
_generator = generator;
_errors = errors;
_attributeEmitter = new AttributeEmitter(_typeReference);
_namespacePrefix = namespacePrefix;
// generate map for inherited types and prefixed types
_namespaceMap = new Dictionary();
_onTypeGenerated = new EventHandler(TypeGeneratedEventHandler);
_onPropertyGenerated = new EventHandler(PropertyGeneratedEventHandler);
//// This constructor can be called multiple times with the same EntityClassGenerator. That is, many instances
//// of the ClientApiGenerator can add handlers to one instance of the EntityClassGenerator.
//// Make sure the handlers are not left on the EntityClassGenerator after the ClientApiGenerator is no longer in use.
//// See the Dispose method
_generator.OnTypeGenerated += _onTypeGenerated;
_generator.OnPropertyGenerated += _onPropertyGenerated;
}
public void Dispose()
{
//// Make sure the handlers are not left on the EntityClassGenerator after the ClientApiGenerator is no longer in use.
_generator.OnTypeGenerated -= _onTypeGenerated;
_generator.OnPropertyGenerated -= _onPropertyGenerated;
}
internal EdmItemCollection EdmItemCollection
{
get { return this._edmItemCollection; }
}
public string NamespacePrefix
{
get { return this._namespacePrefix; }
}
public Dictionary NamespaceMap
{
get { return this._namespaceMap; }
}
///
/// Does code generation emits collections inherited from DataServiceCollection
///
internal bool UseDataServiceCollection
{
get { return _generator.UseDataServiceCollection; }
}
/// Version for which to generate code.
internal DataServiceCodeVersion Version
{
get { return _generator.Version; }
}
///
/// Parses a source Schema and outputs client-side generated code to
/// the output TextWriter.
///
/// The source Schema
/// The TextWriter in which to write the output
/// The Uri for the output. Can be null.
/// A list of GeneratorErrors.
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification="Reviewed")]
internal void GenerateCode(LazyTextWriterCreator target)
{
Debug.Assert(target != null, "target parameter is null");
IndentedTextWriter indentedTextWriter = null;
System.IO.Stream tempFileStream = null;
System.IO.StreamReader reader = null;
System.IO.StreamWriter writer = null;
TempFileCollection tempFiles = null;
try
{
CodeDomProvider provider = null;
switch (Language)
{
case LanguageOption.GenerateCSharpCode:
provider = new Microsoft.CSharp.CSharpCodeProvider();
break;
case LanguageOption.GenerateVBCode:
provider = new Microsoft.VisualBasic.VBCodeProvider();
break;
}
_isLanguageCaseSensitive = (provider.LanguageOptions & LanguageOptions.CaseInsensitive) == 0;
new NamespaceEmitter(this, this.NamespacePrefix, target.TargetFilePath).Emit();
// if there were errors we don't need the output file
if (RealErrorsExist)
{
return;
}
if (FixUps.Count == 0 || !FixUpCollection.IsLanguageSupported(Language))
{
indentedTextWriter = new IndentedTextWriter(target.GetOrCreateTextWriter(), "\t");
}
else
{
// need to write to a temporary file so we can do fixups...
tempFiles = new TempFileCollection(Path.GetTempPath());
string filename = Path.Combine(tempFiles.TempDir, "EdmCodeGenFixup-" + Guid.NewGuid().ToString() + ".tmp");
tempFiles.AddFile(filename, false);
tempFileStream = new System.IO.FileStream(filename, System.IO.FileMode.CreateNew, System.IO.FileAccess.ReadWrite,
System.IO.FileShare.None);
indentedTextWriter = new IndentedTextWriter(new System.IO.StreamWriter(tempFileStream), "\t");
}
CodeGeneratorOptions styleOptions = new CodeGeneratorOptions();
styleOptions.BracingStyle = "C";
styleOptions.BlankLinesBetweenMembers = false;
styleOptions.VerbatimOrder = true;
provider.GenerateCodeFromCompileUnit(CompileUnit, indentedTextWriter, styleOptions);
// if we wrote to a temp file need to post process the file...
if (tempFileStream != null)
{
indentedTextWriter.Flush();
tempFileStream.Seek(0, System.IO.SeekOrigin.Begin);
reader = new System.IO.StreamReader(tempFileStream);
FixUps.Do(reader, target.GetOrCreateTextWriter(), Language, !String.IsNullOrEmpty(SourceObjectNamespaceName));
}
}
catch (System.UnauthorizedAccessException ex)
{
AddError(ModelBuilderErrorCode.SecurityError, EdmSchemaErrorSeverity.Error, ex);
}
catch (System.IO.FileNotFoundException ex)
{
AddError(ModelBuilderErrorCode.FileNotFound, EdmSchemaErrorSeverity.Error, ex);
}
catch (System.Security.SecurityException ex)
{
AddError(ModelBuilderErrorCode.SecurityError, EdmSchemaErrorSeverity.Error, ex);
}
catch (System.IO.DirectoryNotFoundException ex)
{
AddError(ModelBuilderErrorCode.DirectoryNotFound, EdmSchemaErrorSeverity.Error, ex);
}
catch (System.IO.IOException ex)
{
AddError(ModelBuilderErrorCode.IOException, EdmSchemaErrorSeverity.Error, ex);
}
finally
{
if (indentedTextWriter != null)
{
indentedTextWriter.Close();
}
if (tempFileStream != null)
{
tempFileStream.Close();
}
if (tempFiles != null)
{
tempFiles.Delete();
((IDisposable)tempFiles).Dispose();
}
if (reader != null)
{
reader.Close();
}
if (writer != null)
{
writer.Close();
}
}
}
///
/// Verification code invoked for types
///
/// The type being generated
internal void VerifyLanguageCaseSensitiveCompatibilityForType(GlobalItem item)
{
if (_isLanguageCaseSensitive)
{
return; // no validation necessary
}
try
{
_edmItemCollection.GetItem(
Identity(item),
true // ignore case
);
}
catch (InvalidOperationException ex)
{
AddError(ModelBuilderErrorCode.IncompatibleSettingForCaseSensitiveOption, EdmSchemaErrorSeverity.Error, ex);
}
}
///
/// Verification code invoked for properties
///
/// The property or navigation property being generated
internal void VerifyLanguageCaseSensitiveCompatibilityForProperty(EdmMember item)
{
if (_isLanguageCaseSensitive)
{
return; // no validation necessary
}
Debug.Assert(item != null);
ReadOnlyMetadataCollection members = item.DeclaringType.Members;
HashSet set = new HashSet(StringComparer.OrdinalIgnoreCase);
foreach (EdmMember member in members)
{
if (set.Contains(Identity(member)) &&
String.Equals(Identity(item), Identity(member), StringComparison.OrdinalIgnoreCase))
{
AddError(ModelBuilderErrorCode.IncompatibleSettingForCaseSensitiveOption, EdmSchemaErrorSeverity.Error,
new InvalidOperationException(Strings.PropertyExistsWithDifferentCase(Identity(item))));
}
else
{
set.Add(Identity(member));
}
}
}
///
/// Verification code invoked for entity sets
///
/// The entity container being generated
internal void VerifyLanguageCaseSensitiveCompatibilityForEntitySet(System.Data.Metadata.Edm.EntityContainer item)
{
if (_isLanguageCaseSensitive)
{
return; // no validation necessary
}
Debug.Assert(item != null);
HashSet set = new HashSet(StringComparer.OrdinalIgnoreCase);
foreach (EntitySetBase entitySetBase in item.BaseEntitySets)
{
if (Helper.IsEntitySet(entitySetBase))
{
EntitySet entitySet = (EntitySet)entitySetBase;
if (set.Contains(Identity(entitySet)))
{
AddError(ModelBuilderErrorCode.IncompatibleSettingForCaseSensitiveOption, EdmSchemaErrorSeverity.Error,
new InvalidOperationException(Strings.EntitySetExistsWithDifferentCase(Identity(entitySet))));
}
else
{
set.Add(Identity(entitySet));
}
}
}
}
#endregion
#region Internal Properties
internal LanguageOption Language
{
get
{
return _generator.LanguageOption;
}
}
internal TypeReference TypeReference
{
get { return _typeReference; }
}
internal CodeCompileUnit CompileUnit
{
get
{
if (_compileUnit == null)
_compileUnit = new CodeCompileUnit();
return _compileUnit;
}
}
public void AddError(string message, ModelBuilderErrorCode errorCode, EdmSchemaErrorSeverity severity)
{
}
public void AddError(ModelBuilderErrorCode errorCode, EdmSchemaErrorSeverity severity, Exception ex)
{
}
internal void AddError(string message, ModelBuilderErrorCode errorCode, EdmSchemaErrorSeverity severity, Exception ex)
{
}
///
/// Check collection for any real errors (Severity != Warning)
///
public bool RealErrorsExist
{
get
{
foreach (EdmSchemaError error in _errors)
{
if (error.Severity != EdmSchemaErrorSeverity.Warning)
return true;
}
return false;
}
}
public IEnumerable GetSourceTypes()
{
foreach (EntityContainer container in _edmItemCollection.GetItems())
{
BuiltInTypeKind kind = container.BuiltInTypeKind;
yield return container;
}
foreach (EdmType item in _edmItemCollection.GetItems())
{
switch (item.BuiltInTypeKind)
{
case BuiltInTypeKind.AssociationType:
case BuiltInTypeKind.ComplexType:
case BuiltInTypeKind.EntityType:
yield return item;
break;
case BuiltInTypeKind.EdmFunction:
case BuiltInTypeKind.PrimitiveType:
break;
default:
Debug.Assert(false, item.BuiltInTypeKind.ToString());
break;
}
}
}
public string GetClientTypeNamespace(string serviceTypeNamespace)
{
if (string.IsNullOrEmpty(this.NamespacePrefix)) return serviceTypeNamespace;
if (string.IsNullOrEmpty(serviceTypeNamespace) ||
((this.DefaultContainerNamespace != null) && (this.DefaultContainerNamespace == serviceTypeNamespace)))
{
return this.NamespacePrefix;
}
else
{
return this.NamespacePrefix + "." + serviceTypeNamespace;
}
}
public string GetContainerNamespace(EntityContainer container)
{
if (container == null) return null;
string namespaceName = null;
EntitySetBase baseEntitySet = container.BaseEntitySets.FirstOrDefault();
if (null != baseEntitySet)
{
namespaceName = baseEntitySet.ElementType.NamespaceName;
}
return namespaceName;
}
public CodeTypeReference GetLeastPossibleQualifiedTypeReference(EdmType type)
{
string typeRef;
string clientNamespace = GetClientTypeNamespace(type.NamespaceName);
if (clientNamespace == SourceEdmNamespaceName)
{
// we are already generating in this namespace, no need to qualify it
typeRef = type.Name;
}
else
{
typeRef = GetObjectNamespace(clientNamespace) + "." + type.Name;
}
return TypeReference.FromString(typeRef);
}
public string SourceEdmNamespaceName
{
get
{
if (null != _sourceEdmNamespaceName)
{
return _sourceEdmNamespaceName;
}
//
foreach (GlobalItem item in GetSourceTypes())
{
EdmType edm = item as EdmType;
if (null != edm)
{
return edm.NamespaceName;
}
}
return null;
}
set
{
_sourceEdmNamespaceName = value;
}
}
public string DefaultContainerNamespace
{
get { return _defaultContainerNamespace; }
set { _defaultContainerNamespace = value; }
}
public string SourceObjectNamespaceName
{
get
{
string sourceEdmNamespaceName = SourceEdmNamespaceName;
if (!String.IsNullOrEmpty(sourceEdmNamespaceName))
{
return GetObjectNamespace(sourceEdmNamespaceName);
}
return null;
}
}
private string GetObjectNamespace(string csdlNamespaceName)
{
Debug.Assert(csdlNamespaceName != null, "csdlNamespaceName is null");
string objectNamespace;
if (_generator.EdmToObjectNamespaceMap.TryGetObjectNamespace(csdlNamespaceName, out objectNamespace))
{
return objectNamespace;
}
return csdlNamespaceName;
}
///
///
///
///
internal FixUpCollection FixUps
{
get
{
if (_fixUps == null)
_fixUps = new FixUpCollection();
return _fixUps;
}
}
internal AttributeEmitter AttributeEmitter
{
get { return _attributeEmitter; }
}
internal bool IsLanguageCaseSensitive
{
get { return _isLanguageCaseSensitive; }
}
internal StringComparison LanguageAppropriateStringComparer
{
get
{
if (IsLanguageCaseSensitive)
{
return StringComparison.Ordinal;
}
else
{
return StringComparison.OrdinalIgnoreCase;
}
}
}
///
/// Helper method that raises the TypeGenerated event
///
/// The event arguments passed to the subscriber
internal void RaiseTypeGeneratedEvent(TypeGeneratedEventArgs eventArgs)
{
_generator.RaiseTypeGeneratedEvent(eventArgs);
}
///
/// Helper method that raises the PropertyGenerated event
///
/// The event arguments passed to the subscriber
internal void RaisePropertyGeneratedEvent(PropertyGeneratedEventArgs eventArgs)
{
_generator.RaisePropertyGeneratedEvent(eventArgs);
}
///
/// Gets the collection type to be returned for a multi-valued navigation property.
///
/// Type name which is decided based on UseDataServiceCollection setting.
internal string GetRelationshipMultiplicityManyCollectionTypeName()
{
return this.UseDataServiceCollection ? "System.Data.Services.Client.DataServiceCollection" : "System.Collections.ObjectModel.Collection";
}
#endregion
private static string Identity(EdmMember member)
{
return member.ToString();
}
private static string Identity(EntitySetBase entitySet)
{
return entitySet.ToString();
}
private static string Identity(MetadataItem item)
{
return item.ToString();
}
private void TypeGeneratedEventHandler(object sender, TypeGeneratedEventArgs eventArgs)
{
if (!this.UseDataServiceCollection)
{
return;
}
if (eventArgs.TypeSource.BuiltInTypeKind != BuiltInTypeKind.EntityType &&
eventArgs.TypeSource.BuiltInTypeKind != BuiltInTypeKind.ComplexType)
{
return;
}
if (eventArgs.TypeSource.BuiltInTypeKind == BuiltInTypeKind.EntityType)
{
// Generate EntitySetAttribute only if there is exactly one entity set associated
// with the entity type. The DataServiceEntitySetAttribute is not generated for ComplexType(s).
EntitySetBase entitySet = this.GetUniqueEntitySetForType((EntityType)eventArgs.TypeSource);
if (entitySet != null)
{
List additionalAttributes = eventArgs.AdditionalAttributes;
CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(
new CodeTypeReference(typeof(System.Data.Services.Common.EntitySetAttribute),
CodeTypeReferenceOptions.GlobalReference), new CodeAttributeArgument(new CodePrimitiveExpression(entitySet.Name)));
additionalAttributes.Add(attribute);
}
}
//// Determine if type being generated has a base type
if (eventArgs.BaseType != null && !String.IsNullOrEmpty(eventArgs.BaseType.BaseType))
{
if (this.GetSourceTypes().Where(x => x.BuiltInTypeKind == BuiltInTypeKind.EntityType).Where(x => ((EntityType)x).Name == eventArgs.BaseType.BaseType).Count() != 0)
{
//// Don't generate the PropertyChanged event and OnPropertyChanged method for derived type classes
return;
}
}
//// Add the INotifyPropertyChanged interface
List additionalInterfaces = eventArgs.AdditionalInterfaces;
additionalInterfaces.Add(typeof(System.ComponentModel.INotifyPropertyChanged));
//// Add the implementation of the INotifyPropertyChanged interface
//// Generate this code:
////
//// CSharp:
////
//// public event global::System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
////
//// protected virtual void OnPropertyChanged(string property) {
//// if ((this.PropertyChanged != null)) {
//// this.PropertyChanged(this, new global::System.ComponentModel.PropertyChangedEventArgs(property));
//// }
//// }
////
//// Visual Basic:
////
//// Public Event PropertyChanged As Global.System.ComponentModel.PropertyChangedEventHandler Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
//// Protected Overridable Sub OnPropertyChanged(ByVal [property] As String)
//// If (Not (Me.PropertyChangedEvent) Is Nothing) Then
//// RaiseEvent PropertyChanged(Me, New Global.System.ComponentModel.PropertyChangedEventArgs([property]))
//// End If
//// End Sub
CodeMemberEvent propertyChangedEvent = new CodeMemberEvent();
propertyChangedEvent.Type = new CodeTypeReference(typeof(System.ComponentModel.PropertyChangedEventHandler), CodeTypeReferenceOptions.GlobalReference);
propertyChangedEvent.Name = "PropertyChanged";
propertyChangedEvent.Attributes = MemberAttributes.Public;
propertyChangedEvent.ImplementationTypes.Add(typeof(System.ComponentModel.INotifyPropertyChanged));
AttributeEmitter.AddGeneratedCodeAttribute(propertyChangedEvent);
eventArgs.AdditionalMembers.Add(propertyChangedEvent);
CodeMemberMethod propertyChangedMethod = new CodeMemberMethod();
propertyChangedMethod.Name = "OnPropertyChanged";
propertyChangedMethod.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(System.String), CodeTypeReferenceOptions.GlobalReference), "property"));
propertyChangedMethod.ReturnType = new CodeTypeReference(typeof(void));
AttributeEmitter.AddGeneratedCodeAttribute(propertyChangedMethod);
propertyChangedMethod.Statements.Add(
new CodeConditionStatement(
new CodeBinaryOperatorExpression(
new CodeEventReferenceExpression(new CodeThisReferenceExpression(), "PropertyChanged"),
CodeBinaryOperatorType.IdentityInequality,
new CodePrimitiveExpression(null)),
new CodeExpressionStatement(
new CodeDelegateInvokeExpression(
new CodeEventReferenceExpression(new CodeThisReferenceExpression(), "PropertyChanged"),
new CodeExpression[] {
new CodeThisReferenceExpression(),
new CodeObjectCreateExpression(new CodeTypeReference(typeof(System.ComponentModel.PropertyChangedEventArgs), CodeTypeReferenceOptions.GlobalReference), new CodeArgumentReferenceExpression("property"))
}))));
propertyChangedMethod.Attributes = MemberAttributes.Family;
eventArgs.AdditionalMembers.Add(propertyChangedMethod);
}
private void PropertyGeneratedEventHandler(object sender, PropertyGeneratedEventArgs eventArgs)
{
if (!this.UseDataServiceCollection)
{
return;
}
if (eventArgs.PropertySource.BuiltInTypeKind != BuiltInTypeKind.EdmProperty &&
eventArgs.PropertySource.BuiltInTypeKind != BuiltInTypeKind.NavigationProperty)
{
return;
}
if (((EdmMember)eventArgs.PropertySource).DeclaringType.BuiltInTypeKind != BuiltInTypeKind.EntityType &&
((EdmMember)eventArgs.PropertySource).DeclaringType.BuiltInTypeKind != BuiltInTypeKind.ComplexType)
{
return;
}
string name = eventArgs.PropertySource.BuiltInTypeKind == BuiltInTypeKind.EdmProperty ? ((EdmProperty)eventArgs.PropertySource).Name : ((NavigationProperty)eventArgs.PropertySource).Name;
// Add call to the OnPropertyChanged method
eventArgs.AdditionalAfterSetStatements.Add(new CodeExpressionStatement(new CodeMethodInvokeExpression(
new CodeThisReferenceExpression(), "OnPropertyChanged",
new CodeExpression[] { new CodePrimitiveExpression(name) }
)));
}
/// Given an entity type, returns the corresponding entity set if it's unique.
/// Given entity type.
/// Corresponding entity set if it's unique, null otherwise.
private EntitySetBase GetUniqueEntitySetForType(EntityType entityType)
{
HashSet entitySets = new HashSet(EqualityComparerEntitySet.Default);
foreach (EntityContainer container in this.EdmItemCollection.GetItems())
{
bool alreadyAdded = false;
foreach (EntitySetBase es in container.BaseEntitySets
.Where(x => x.BuiltInTypeKind == BuiltInTypeKind.EntitySet &&
x.ElementType == entityType))
{
if (alreadyAdded == true)
{
return null;
}
alreadyAdded = true;
entitySets.Add(es);
}
}
if (entitySets.Count == 1)
{
return entitySets.Single();
}
else
{
return null;
}
}
/// Equality comparer used for deciding whether to add EntitySet attribute to an entity type.
public class EqualityComparerEntitySet : IEqualityComparer
{
/// Cached singleton comparer.
private static EqualityComparerEntitySet _comparer = new EqualityComparerEntitySet();
/// Gets the singleton comparer.
public static EqualityComparerEntitySet Default
{
get
{
return _comparer;
}
}
#region IEqualityComparer Members
/// Equality check.
/// Left.
/// Right.
/// true if names are same, false otherwise.
public bool Equals(EntitySetBase x, EntitySetBase y)
{
return (x == null && y == null) ||
(x != null && y != null && x.Name == y.Name);
}
/// Gets hash code for EntitySetBase.
/// Object for which to get hash code.
/// Hash code for the name.
public int GetHashCode(EntitySetBase obj)
{
return (null != obj) ? obj.Name.GetHashCode() : 0;
}
#endregion
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//----------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Generic;
using System.Data.EntityModel.Emitters;
using System.Data.Metadata.Edm;
using System.Data.Services.Design;
using System.Diagnostics;
using System.IO;
using System.Linq;
namespace System.Data.Metadata.Edm
{
internal static partial class Helper
{
internal static bool IsCollectionType(GlobalItem item)
{
return (BuiltInTypeKind.CollectionType == item.BuiltInTypeKind);
}
internal static bool IsComplexType(EdmType type)
{
return (BuiltInTypeKind.ComplexType == type.BuiltInTypeKind);
}
internal static bool IsEntitySet(EntitySetBase entitySetBase)
{
return BuiltInTypeKind.EntitySet == entitySetBase.BuiltInTypeKind;
}
internal static bool IsPrimitiveType(EdmType type)
{
return (BuiltInTypeKind.PrimitiveType == type.BuiltInTypeKind);
}
}
internal static class TypeSemantics
{
internal static bool IsComplexType(TypeUsage type)
{
return Helper.IsComplexType(type.EdmType);
}
}
internal static class EdmProviderManifest
{
// System Facet Info
///
/// Name of the MaxLength Facet
///
internal const string MaxLengthFacetName = "MaxLength";
///
/// Name of the Unicode Facet
///
internal const string UnicodeFacetName = "Unicode";
///
/// Name of the FixedLength Facet
///
internal const string FixedLengthFacetName = "FixedLength";
///
/// Name of the DateTimeKind Facet
///
internal const string DateTimeKindFacetName = "DateTimeKind";
///
/// Name of the PreserveSeconds Facet
///
internal const string PreserveSecondsFacetName = "PreserveSeconds";
///
/// Name of the Precision Facet
///
internal const string PrecisionFacetName = "Precision";
///
/// Name of the Scale Facet
///
internal const string ScaleFacetName = "Scale";
///
/// Name of the Nullable Facet
///
internal const string NullableFacetName = "Nullable";
///
/// Name of the DefaultValue Facet
///
internal const string DefaultValueFacetName = "DefaultValue";
/////
///// Name of the DefaultType metadata property
/////
//internal const string DefaultTypeMetadataPropertyName = "DefaultType";
///
/// Name of the Collation Facet
///
internal const string CollationFacetName = "Collation";
}
internal static class TypeSystem
{
private static readonly System.Reflection.MethodInfo s_getDefaultMethod = typeof(TypeSystem).GetMethod("GetDefault", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
private static T GetDefault() { return default(T); }
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining | System.Runtime.CompilerServices.MethodImplOptions.NoOptimization)]
internal static object GetDefaultValue(Type type)
{
// null is always the default for non value types and Nullable<>
if (!type.IsValueType ||
(type.IsGenericType &&
typeof(Nullable<>) == type.GetGenericTypeDefinition()))
{
return null;
}
System.Reflection.MethodInfo getDefaultMethod = s_getDefaultMethod.MakeGenericMethod(type);
object defaultValue = getDefaultMethod.Invoke(null, new object[] { });
return defaultValue;
}
}
internal static class Schema
{
public const string CodeGenerationSchemaNamespace = "http://schemas.microsoft.com/ado/2006/04/codegeneration";
}
}
namespace System.Data.EntityModel
{
///
/// Summary description for ClientApiGenerator.
///
internal sealed class ClientApiGenerator : IDisposable
{
#region Instance Fields
private CodeCompileUnit _compileUnit;
private bool _isLanguageCaseSensitive = true;
private EdmItemCollection _edmItemCollection;
private FixUpCollection _fixUps;
private AttributeEmitter _attributeEmitter;
private EntityClassGenerator _generator;
private List _errors;
private TypeReference _typeReference = new TypeReference();
private string _sourceEdmNamespaceName;
private string _defaultContainerNamespace;
private string _namespacePrefix;
private Dictionary _namespaceMap;
private EventHandler _onTypeGenerated;
private EventHandler _onPropertyGenerated;
#endregion
#region Public Methods
public ClientApiGenerator(object sourceSchema, EdmItemCollection edmItemCollection, EntityClassGenerator generator, List errors, string namespacePrefix)
{
Debug.Assert(edmItemCollection != null, "edmItemCollection is null");
Debug.Assert(generator != null, "generator is null");
Debug.Assert(errors != null, "errors is null");
_edmItemCollection = edmItemCollection;
_generator = generator;
_errors = errors;
_attributeEmitter = new AttributeEmitter(_typeReference);
_namespacePrefix = namespacePrefix;
// generate map for inherited types and prefixed types
_namespaceMap = new Dictionary();
_onTypeGenerated = new EventHandler(TypeGeneratedEventHandler);
_onPropertyGenerated = new EventHandler(PropertyGeneratedEventHandler);
//// This constructor can be called multiple times with the same EntityClassGenerator. That is, many instances
//// of the ClientApiGenerator can add handlers to one instance of the EntityClassGenerator.
//// Make sure the handlers are not left on the EntityClassGenerator after the ClientApiGenerator is no longer in use.
//// See the Dispose method
_generator.OnTypeGenerated += _onTypeGenerated;
_generator.OnPropertyGenerated += _onPropertyGenerated;
}
public void Dispose()
{
//// Make sure the handlers are not left on the EntityClassGenerator after the ClientApiGenerator is no longer in use.
_generator.OnTypeGenerated -= _onTypeGenerated;
_generator.OnPropertyGenerated -= _onPropertyGenerated;
}
internal EdmItemCollection EdmItemCollection
{
get { return this._edmItemCollection; }
}
public string NamespacePrefix
{
get { return this._namespacePrefix; }
}
public Dictionary NamespaceMap
{
get { return this._namespaceMap; }
}
///
/// Does code generation emits collections inherited from DataServiceCollection
///
internal bool UseDataServiceCollection
{
get { return _generator.UseDataServiceCollection; }
}
/// Version for which to generate code.
internal DataServiceCodeVersion Version
{
get { return _generator.Version; }
}
///
/// Parses a source Schema and outputs client-side generated code to
/// the output TextWriter.
///
/// The source Schema
/// The TextWriter in which to write the output
/// The Uri for the output. Can be null.
/// A list of GeneratorErrors.
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification="Reviewed")]
internal void GenerateCode(LazyTextWriterCreator target)
{
Debug.Assert(target != null, "target parameter is null");
IndentedTextWriter indentedTextWriter = null;
System.IO.Stream tempFileStream = null;
System.IO.StreamReader reader = null;
System.IO.StreamWriter writer = null;
TempFileCollection tempFiles = null;
try
{
CodeDomProvider provider = null;
switch (Language)
{
case LanguageOption.GenerateCSharpCode:
provider = new Microsoft.CSharp.CSharpCodeProvider();
break;
case LanguageOption.GenerateVBCode:
provider = new Microsoft.VisualBasic.VBCodeProvider();
break;
}
_isLanguageCaseSensitive = (provider.LanguageOptions & LanguageOptions.CaseInsensitive) == 0;
new NamespaceEmitter(this, this.NamespacePrefix, target.TargetFilePath).Emit();
// if there were errors we don't need the output file
if (RealErrorsExist)
{
return;
}
if (FixUps.Count == 0 || !FixUpCollection.IsLanguageSupported(Language))
{
indentedTextWriter = new IndentedTextWriter(target.GetOrCreateTextWriter(), "\t");
}
else
{
// need to write to a temporary file so we can do fixups...
tempFiles = new TempFileCollection(Path.GetTempPath());
string filename = Path.Combine(tempFiles.TempDir, "EdmCodeGenFixup-" + Guid.NewGuid().ToString() + ".tmp");
tempFiles.AddFile(filename, false);
tempFileStream = new System.IO.FileStream(filename, System.IO.FileMode.CreateNew, System.IO.FileAccess.ReadWrite,
System.IO.FileShare.None);
indentedTextWriter = new IndentedTextWriter(new System.IO.StreamWriter(tempFileStream), "\t");
}
CodeGeneratorOptions styleOptions = new CodeGeneratorOptions();
styleOptions.BracingStyle = "C";
styleOptions.BlankLinesBetweenMembers = false;
styleOptions.VerbatimOrder = true;
provider.GenerateCodeFromCompileUnit(CompileUnit, indentedTextWriter, styleOptions);
// if we wrote to a temp file need to post process the file...
if (tempFileStream != null)
{
indentedTextWriter.Flush();
tempFileStream.Seek(0, System.IO.SeekOrigin.Begin);
reader = new System.IO.StreamReader(tempFileStream);
FixUps.Do(reader, target.GetOrCreateTextWriter(), Language, !String.IsNullOrEmpty(SourceObjectNamespaceName));
}
}
catch (System.UnauthorizedAccessException ex)
{
AddError(ModelBuilderErrorCode.SecurityError, EdmSchemaErrorSeverity.Error, ex);
}
catch (System.IO.FileNotFoundException ex)
{
AddError(ModelBuilderErrorCode.FileNotFound, EdmSchemaErrorSeverity.Error, ex);
}
catch (System.Security.SecurityException ex)
{
AddError(ModelBuilderErrorCode.SecurityError, EdmSchemaErrorSeverity.Error, ex);
}
catch (System.IO.DirectoryNotFoundException ex)
{
AddError(ModelBuilderErrorCode.DirectoryNotFound, EdmSchemaErrorSeverity.Error, ex);
}
catch (System.IO.IOException ex)
{
AddError(ModelBuilderErrorCode.IOException, EdmSchemaErrorSeverity.Error, ex);
}
finally
{
if (indentedTextWriter != null)
{
indentedTextWriter.Close();
}
if (tempFileStream != null)
{
tempFileStream.Close();
}
if (tempFiles != null)
{
tempFiles.Delete();
((IDisposable)tempFiles).Dispose();
}
if (reader != null)
{
reader.Close();
}
if (writer != null)
{
writer.Close();
}
}
}
///
/// Verification code invoked for types
///
/// The type being generated
internal void VerifyLanguageCaseSensitiveCompatibilityForType(GlobalItem item)
{
if (_isLanguageCaseSensitive)
{
return; // no validation necessary
}
try
{
_edmItemCollection.GetItem(
Identity(item),
true // ignore case
);
}
catch (InvalidOperationException ex)
{
AddError(ModelBuilderErrorCode.IncompatibleSettingForCaseSensitiveOption, EdmSchemaErrorSeverity.Error, ex);
}
}
///
/// Verification code invoked for properties
///
/// The property or navigation property being generated
internal void VerifyLanguageCaseSensitiveCompatibilityForProperty(EdmMember item)
{
if (_isLanguageCaseSensitive)
{
return; // no validation necessary
}
Debug.Assert(item != null);
ReadOnlyMetadataCollection members = item.DeclaringType.Members;
HashSet set = new HashSet(StringComparer.OrdinalIgnoreCase);
foreach (EdmMember member in members)
{
if (set.Contains(Identity(member)) &&
String.Equals(Identity(item), Identity(member), StringComparison.OrdinalIgnoreCase))
{
AddError(ModelBuilderErrorCode.IncompatibleSettingForCaseSensitiveOption, EdmSchemaErrorSeverity.Error,
new InvalidOperationException(Strings.PropertyExistsWithDifferentCase(Identity(item))));
}
else
{
set.Add(Identity(member));
}
}
}
///
/// Verification code invoked for entity sets
///
/// The entity container being generated
internal void VerifyLanguageCaseSensitiveCompatibilityForEntitySet(System.Data.Metadata.Edm.EntityContainer item)
{
if (_isLanguageCaseSensitive)
{
return; // no validation necessary
}
Debug.Assert(item != null);
HashSet set = new HashSet(StringComparer.OrdinalIgnoreCase);
foreach (EntitySetBase entitySetBase in item.BaseEntitySets)
{
if (Helper.IsEntitySet(entitySetBase))
{
EntitySet entitySet = (EntitySet)entitySetBase;
if (set.Contains(Identity(entitySet)))
{
AddError(ModelBuilderErrorCode.IncompatibleSettingForCaseSensitiveOption, EdmSchemaErrorSeverity.Error,
new InvalidOperationException(Strings.EntitySetExistsWithDifferentCase(Identity(entitySet))));
}
else
{
set.Add(Identity(entitySet));
}
}
}
}
#endregion
#region Internal Properties
internal LanguageOption Language
{
get
{
return _generator.LanguageOption;
}
}
internal TypeReference TypeReference
{
get { return _typeReference; }
}
internal CodeCompileUnit CompileUnit
{
get
{
if (_compileUnit == null)
_compileUnit = new CodeCompileUnit();
return _compileUnit;
}
}
public void AddError(string message, ModelBuilderErrorCode errorCode, EdmSchemaErrorSeverity severity)
{
}
public void AddError(ModelBuilderErrorCode errorCode, EdmSchemaErrorSeverity severity, Exception ex)
{
}
internal void AddError(string message, ModelBuilderErrorCode errorCode, EdmSchemaErrorSeverity severity, Exception ex)
{
}
///
/// Check collection for any real errors (Severity != Warning)
///
public bool RealErrorsExist
{
get
{
foreach (EdmSchemaError error in _errors)
{
if (error.Severity != EdmSchemaErrorSeverity.Warning)
return true;
}
return false;
}
}
public IEnumerable GetSourceTypes()
{
foreach (EntityContainer container in _edmItemCollection.GetItems())
{
BuiltInTypeKind kind = container.BuiltInTypeKind;
yield return container;
}
foreach (EdmType item in _edmItemCollection.GetItems())
{
switch (item.BuiltInTypeKind)
{
case BuiltInTypeKind.AssociationType:
case BuiltInTypeKind.ComplexType:
case BuiltInTypeKind.EntityType:
yield return item;
break;
case BuiltInTypeKind.EdmFunction:
case BuiltInTypeKind.PrimitiveType:
break;
default:
Debug.Assert(false, item.BuiltInTypeKind.ToString());
break;
}
}
}
public string GetClientTypeNamespace(string serviceTypeNamespace)
{
if (string.IsNullOrEmpty(this.NamespacePrefix)) return serviceTypeNamespace;
if (string.IsNullOrEmpty(serviceTypeNamespace) ||
((this.DefaultContainerNamespace != null) && (this.DefaultContainerNamespace == serviceTypeNamespace)))
{
return this.NamespacePrefix;
}
else
{
return this.NamespacePrefix + "." + serviceTypeNamespace;
}
}
public string GetContainerNamespace(EntityContainer container)
{
if (container == null) return null;
string namespaceName = null;
EntitySetBase baseEntitySet = container.BaseEntitySets.FirstOrDefault();
if (null != baseEntitySet)
{
namespaceName = baseEntitySet.ElementType.NamespaceName;
}
return namespaceName;
}
public CodeTypeReference GetLeastPossibleQualifiedTypeReference(EdmType type)
{
string typeRef;
string clientNamespace = GetClientTypeNamespace(type.NamespaceName);
if (clientNamespace == SourceEdmNamespaceName)
{
// we are already generating in this namespace, no need to qualify it
typeRef = type.Name;
}
else
{
typeRef = GetObjectNamespace(clientNamespace) + "." + type.Name;
}
return TypeReference.FromString(typeRef);
}
public string SourceEdmNamespaceName
{
get
{
if (null != _sourceEdmNamespaceName)
{
return _sourceEdmNamespaceName;
}
//
foreach (GlobalItem item in GetSourceTypes())
{
EdmType edm = item as EdmType;
if (null != edm)
{
return edm.NamespaceName;
}
}
return null;
}
set
{
_sourceEdmNamespaceName = value;
}
}
public string DefaultContainerNamespace
{
get { return _defaultContainerNamespace; }
set { _defaultContainerNamespace = value; }
}
public string SourceObjectNamespaceName
{
get
{
string sourceEdmNamespaceName = SourceEdmNamespaceName;
if (!String.IsNullOrEmpty(sourceEdmNamespaceName))
{
return GetObjectNamespace(sourceEdmNamespaceName);
}
return null;
}
}
private string GetObjectNamespace(string csdlNamespaceName)
{
Debug.Assert(csdlNamespaceName != null, "csdlNamespaceName is null");
string objectNamespace;
if (_generator.EdmToObjectNamespaceMap.TryGetObjectNamespace(csdlNamespaceName, out objectNamespace))
{
return objectNamespace;
}
return csdlNamespaceName;
}
///
///
///
///
internal FixUpCollection FixUps
{
get
{
if (_fixUps == null)
_fixUps = new FixUpCollection();
return _fixUps;
}
}
internal AttributeEmitter AttributeEmitter
{
get { return _attributeEmitter; }
}
internal bool IsLanguageCaseSensitive
{
get { return _isLanguageCaseSensitive; }
}
internal StringComparison LanguageAppropriateStringComparer
{
get
{
if (IsLanguageCaseSensitive)
{
return StringComparison.Ordinal;
}
else
{
return StringComparison.OrdinalIgnoreCase;
}
}
}
///
/// Helper method that raises the TypeGenerated event
///
/// The event arguments passed to the subscriber
internal void RaiseTypeGeneratedEvent(TypeGeneratedEventArgs eventArgs)
{
_generator.RaiseTypeGeneratedEvent(eventArgs);
}
///
/// Helper method that raises the PropertyGenerated event
///
/// The event arguments passed to the subscriber
internal void RaisePropertyGeneratedEvent(PropertyGeneratedEventArgs eventArgs)
{
_generator.RaisePropertyGeneratedEvent(eventArgs);
}
///
/// Gets the collection type to be returned for a multi-valued navigation property.
///
/// Type name which is decided based on UseDataServiceCollection setting.
internal string GetRelationshipMultiplicityManyCollectionTypeName()
{
return this.UseDataServiceCollection ? "System.Data.Services.Client.DataServiceCollection" : "System.Collections.ObjectModel.Collection";
}
#endregion
private static string Identity(EdmMember member)
{
return member.ToString();
}
private static string Identity(EntitySetBase entitySet)
{
return entitySet.ToString();
}
private static string Identity(MetadataItem item)
{
return item.ToString();
}
private void TypeGeneratedEventHandler(object sender, TypeGeneratedEventArgs eventArgs)
{
if (!this.UseDataServiceCollection)
{
return;
}
if (eventArgs.TypeSource.BuiltInTypeKind != BuiltInTypeKind.EntityType &&
eventArgs.TypeSource.BuiltInTypeKind != BuiltInTypeKind.ComplexType)
{
return;
}
if (eventArgs.TypeSource.BuiltInTypeKind == BuiltInTypeKind.EntityType)
{
// Generate EntitySetAttribute only if there is exactly one entity set associated
// with the entity type. The DataServiceEntitySetAttribute is not generated for ComplexType(s).
EntitySetBase entitySet = this.GetUniqueEntitySetForType((EntityType)eventArgs.TypeSource);
if (entitySet != null)
{
List additionalAttributes = eventArgs.AdditionalAttributes;
CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(
new CodeTypeReference(typeof(System.Data.Services.Common.EntitySetAttribute),
CodeTypeReferenceOptions.GlobalReference), new CodeAttributeArgument(new CodePrimitiveExpression(entitySet.Name)));
additionalAttributes.Add(attribute);
}
}
//// Determine if type being generated has a base type
if (eventArgs.BaseType != null && !String.IsNullOrEmpty(eventArgs.BaseType.BaseType))
{
if (this.GetSourceTypes().Where(x => x.BuiltInTypeKind == BuiltInTypeKind.EntityType).Where(x => ((EntityType)x).Name == eventArgs.BaseType.BaseType).Count() != 0)
{
//// Don't generate the PropertyChanged event and OnPropertyChanged method for derived type classes
return;
}
}
//// Add the INotifyPropertyChanged interface
List additionalInterfaces = eventArgs.AdditionalInterfaces;
additionalInterfaces.Add(typeof(System.ComponentModel.INotifyPropertyChanged));
//// Add the implementation of the INotifyPropertyChanged interface
//// Generate this code:
////
//// CSharp:
////
//// public event global::System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
////
//// protected virtual void OnPropertyChanged(string property) {
//// if ((this.PropertyChanged != null)) {
//// this.PropertyChanged(this, new global::System.ComponentModel.PropertyChangedEventArgs(property));
//// }
//// }
////
//// Visual Basic:
////
//// Public Event PropertyChanged As Global.System.ComponentModel.PropertyChangedEventHandler Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
//// Protected Overridable Sub OnPropertyChanged(ByVal [property] As String)
//// If (Not (Me.PropertyChangedEvent) Is Nothing) Then
//// RaiseEvent PropertyChanged(Me, New Global.System.ComponentModel.PropertyChangedEventArgs([property]))
//// End If
//// End Sub
CodeMemberEvent propertyChangedEvent = new CodeMemberEvent();
propertyChangedEvent.Type = new CodeTypeReference(typeof(System.ComponentModel.PropertyChangedEventHandler), CodeTypeReferenceOptions.GlobalReference);
propertyChangedEvent.Name = "PropertyChanged";
propertyChangedEvent.Attributes = MemberAttributes.Public;
propertyChangedEvent.ImplementationTypes.Add(typeof(System.ComponentModel.INotifyPropertyChanged));
AttributeEmitter.AddGeneratedCodeAttribute(propertyChangedEvent);
eventArgs.AdditionalMembers.Add(propertyChangedEvent);
CodeMemberMethod propertyChangedMethod = new CodeMemberMethod();
propertyChangedMethod.Name = "OnPropertyChanged";
propertyChangedMethod.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(System.String), CodeTypeReferenceOptions.GlobalReference), "property"));
propertyChangedMethod.ReturnType = new CodeTypeReference(typeof(void));
AttributeEmitter.AddGeneratedCodeAttribute(propertyChangedMethod);
propertyChangedMethod.Statements.Add(
new CodeConditionStatement(
new CodeBinaryOperatorExpression(
new CodeEventReferenceExpression(new CodeThisReferenceExpression(), "PropertyChanged"),
CodeBinaryOperatorType.IdentityInequality,
new CodePrimitiveExpression(null)),
new CodeExpressionStatement(
new CodeDelegateInvokeExpression(
new CodeEventReferenceExpression(new CodeThisReferenceExpression(), "PropertyChanged"),
new CodeExpression[] {
new CodeThisReferenceExpression(),
new CodeObjectCreateExpression(new CodeTypeReference(typeof(System.ComponentModel.PropertyChangedEventArgs), CodeTypeReferenceOptions.GlobalReference), new CodeArgumentReferenceExpression("property"))
}))));
propertyChangedMethod.Attributes = MemberAttributes.Family;
eventArgs.AdditionalMembers.Add(propertyChangedMethod);
}
private void PropertyGeneratedEventHandler(object sender, PropertyGeneratedEventArgs eventArgs)
{
if (!this.UseDataServiceCollection)
{
return;
}
if (eventArgs.PropertySource.BuiltInTypeKind != BuiltInTypeKind.EdmProperty &&
eventArgs.PropertySource.BuiltInTypeKind != BuiltInTypeKind.NavigationProperty)
{
return;
}
if (((EdmMember)eventArgs.PropertySource).DeclaringType.BuiltInTypeKind != BuiltInTypeKind.EntityType &&
((EdmMember)eventArgs.PropertySource).DeclaringType.BuiltInTypeKind != BuiltInTypeKind.ComplexType)
{
return;
}
string name = eventArgs.PropertySource.BuiltInTypeKind == BuiltInTypeKind.EdmProperty ? ((EdmProperty)eventArgs.PropertySource).Name : ((NavigationProperty)eventArgs.PropertySource).Name;
// Add call to the OnPropertyChanged method
eventArgs.AdditionalAfterSetStatements.Add(new CodeExpressionStatement(new CodeMethodInvokeExpression(
new CodeThisReferenceExpression(), "OnPropertyChanged",
new CodeExpression[] { new CodePrimitiveExpression(name) }
)));
}
/// Given an entity type, returns the corresponding entity set if it's unique.
/// Given entity type.
/// Corresponding entity set if it's unique, null otherwise.
private EntitySetBase GetUniqueEntitySetForType(EntityType entityType)
{
HashSet entitySets = new HashSet(EqualityComparerEntitySet.Default);
foreach (EntityContainer container in this.EdmItemCollection.GetItems())
{
bool alreadyAdded = false;
foreach (EntitySetBase es in container.BaseEntitySets
.Where(x => x.BuiltInTypeKind == BuiltInTypeKind.EntitySet &&
x.ElementType == entityType))
{
if (alreadyAdded == true)
{
return null;
}
alreadyAdded = true;
entitySets.Add(es);
}
}
if (entitySets.Count == 1)
{
return entitySets.Single();
}
else
{
return null;
}
}
/// Equality comparer used for deciding whether to add EntitySet attribute to an entity type.
public class EqualityComparerEntitySet : IEqualityComparer
{
/// Cached singleton comparer.
private static EqualityComparerEntitySet _comparer = new EqualityComparerEntitySet();
/// Gets the singleton comparer.
public static EqualityComparerEntitySet Default
{
get
{
return _comparer;
}
}
#region IEqualityComparer Members
/// Equality check.
/// Left.
/// Right.
/// true if names are same, false otherwise.
public bool Equals(EntitySetBase x, EntitySetBase y)
{
return (x == null && y == null) ||
(x != null && y != null && x.Name == y.Name);
}
/// Gets hash code for EntitySetBase.
/// Object for which to get hash code.
/// Hash code for the name.
public int GetHashCode(EntitySetBase obj)
{
return (null != obj) ? obj.Name.GetHashCode() : 0;
}
#endregion
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- RelationshipNavigation.cs
- ConnectorMovedEventArgs.cs
- AliasGenerator.cs
- ToolStrip.cs
- MenuItemBinding.cs
- Scheduler.cs
- MemberProjectedSlot.cs
- Random.cs
- MdImport.cs
- SecUtil.cs
- SystemDropShadowChrome.cs
- Setter.cs
- SHA384CryptoServiceProvider.cs
- MemberInfoSerializationHolder.cs
- ResourceReferenceExpressionConverter.cs
- DocumentsTrace.cs
- EmptyQuery.cs
- ContextMarshalException.cs
- FigureHelper.cs
- HtmlControlDesigner.cs
- DataGridAutoGeneratingColumnEventArgs.cs
- ShapingWorkspace.cs
- TabOrder.cs
- CodeFieldReferenceExpression.cs
- ObjectQueryProvider.cs
- While.cs
- SmiEventSink.cs
- DataGrid.cs
- WebCodeGenerator.cs
- GenericXmlSecurityToken.cs
- PeerDuplexChannelListener.cs
- PageVisual.cs
- EdmToObjectNamespaceMap.cs
- ControlBuilder.cs
- Cell.cs
- Registry.cs
- HashSetEqualityComparer.cs
- AppDomain.cs
- ToolStripLabel.cs
- TraceSwitch.cs
- DataGridTextBox.cs
- NativeMethodsOther.cs
- PropertyDescriptor.cs
- ScriptServiceAttribute.cs
- XPathNavigatorKeyComparer.cs
- PasswordTextContainer.cs
- LinqDataSourceDisposeEventArgs.cs
- HScrollProperties.cs
- AutomationElementCollection.cs
- SqlRemoveConstantOrderBy.cs
- DesignerVerbCollection.cs
- Invariant.cs
- EventLogEntry.cs
- EntityViewContainer.cs
- ChangeNode.cs
- DesignerAutoFormatCollection.cs
- CompiledRegexRunner.cs
- CustomLineCap.cs
- OutOfMemoryException.cs
- HitTestWithPointDrawingContextWalker.cs
- TableLayoutCellPaintEventArgs.cs
- DrawingContextDrawingContextWalker.cs
- VScrollBar.cs
- Convert.cs
- FormsAuthenticationUser.cs
- Resources.Designer.cs
- EventLogPermissionAttribute.cs
- PropertyChangedEventManager.cs
- Typography.cs
- UnsettableComboBox.cs
- PerformanceCountersElement.cs
- ResXDataNode.cs
- PreProcessor.cs
- GifBitmapDecoder.cs
- SupportsEventValidationAttribute.cs
- ISAPIRuntime.cs
- ScriptingRoleServiceSection.cs
- SqlWriter.cs
- SmtpLoginAuthenticationModule.cs
- BinaryObjectReader.cs
- WebControl.cs
- AlignmentYValidation.cs
- XmlElement.cs
- ProcessInfo.cs
- DictionaryBase.cs
- MetadataPropertyvalue.cs
- TextRenderer.cs
- CodeIterationStatement.cs
- PriorityQueue.cs
- UndirectedGraph.cs
- X500Name.cs
- WinEventQueueItem.cs
- TableCellCollection.cs
- ListViewItemEventArgs.cs
- InputMethodStateChangeEventArgs.cs
- DateTimeConstantAttribute.cs
- DoubleKeyFrameCollection.cs
- RoleService.cs
- Label.cs
- ViewUtilities.cs