Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / ndp / fx / src / DataWeb / Design / system / Data / EntityModel / Emitters / EntityContainerEmitter.cs / 1 / EntityContainerEmitter.cs
//---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....] // @backupOwner [....] //--------------------------------------------------------------------- using System.CodeDom; using System.Collections.Generic; using System.Data.Services.Design; using System.Data.Services.Design.Common; using System.Data.Metadata.Edm; using System.Data.Objects; using System.Diagnostics; using System.Linq; namespace System.Data.EntityModel.Emitters { ////// This class is responsible for emiting the code for the EntityContainer schema element /// internal sealed class EntityContainerEmitter : SchemaTypeEmitter { #region Fields private const string _onContextCreatedString = "OnContextCreated"; #endregion #region Constructors ////// /// /// /// public EntityContainerEmitter(ClientApiGenerator generator, EntityContainer entityContainer) : base(generator, entityContainer) { } #endregion #region Properties, Methods, Events & Delegates ////// Creates the CodeTypeDeclarations necessary to generate the code for the EntityContainer schema element /// ///public override CodeTypeDeclarationCollection EmitApiClass() { Validate(); // emitter-specific validation // declare the new class // public partial class LOBScenario : ObjectContext CodeTypeDeclaration typeDecl = new CodeTypeDeclaration(Item.Name); typeDecl.IsPartial = true; // raise the TypeGenerated event CodeTypeReference objectContextTypeRef = TypeReference.ObjectContext; TypeGeneratedEventArgs eventArgs = new TypeGeneratedEventArgs(Item, objectContextTypeRef); Generator.RaiseTypeGeneratedEvent(eventArgs); if (eventArgs.BaseType != null && !eventArgs.BaseType.Equals(objectContextTypeRef)) { typeDecl.BaseTypes.Add(eventArgs.BaseType); } else { typeDecl.BaseTypes.Add(TypeReference.ObjectContext); } AddInterfaces(Item.Name, typeDecl, eventArgs.AdditionalInterfaces); CommentEmitter.EmitSummaryComments(Item, typeDecl.Comments); EmitTypeAttributes(Item.Name, typeDecl, eventArgs.AdditionalAttributes); bool needTypeMapper = (0 < this.Generator.NamespaceMap.Count); var q = from a in this.Generator.EdmItemCollection.GetItems () where (a.BaseType != null) && (a.BuiltInTypeKind == BuiltInTypeKind.ComplexType || a.BuiltInTypeKind == BuiltInTypeKind.EntityType) select a; bool hasInheritance = (null != q.FirstOrDefault()); CreateConstructors(typeDecl, needTypeMapper, hasInheritance); // adding partial OnContextCreated method CreateContextPartialMethods(typeDecl); if (needTypeMapper || hasInheritance) { CreateTypeMappingMethods(typeDecl, needTypeMapper, hasInheritance); } foreach (EntitySetBase entitySetBase in Item.BaseEntitySets) { if (Helper.IsEntitySet(entitySetBase)) { EntitySet set = (EntitySet)entitySetBase; CodeMemberProperty codeProperty = CreateEntitySetProperty(set); typeDecl.Members.Add(codeProperty); CodeMemberField codeField = CreateEntitySetField(set); typeDecl.Members.Add(codeField); } } foreach (EntitySetBase entitySetBase in Item.BaseEntitySets) { if (Helper.IsEntitySet(entitySetBase)) { EntitySet set = (EntitySet)entitySetBase; CodeMemberMethod codeProperty = CreateEntitySetAddObjectProperty(set); typeDecl.Members.Add(codeProperty); } } // additional members, if provided by the event subscriber AddMembers(Item.Name, typeDecl, eventArgs.AdditionalMembers); CodeTypeDeclarationCollection typeDecls = new CodeTypeDeclarationCollection(); typeDecls.Add(typeDecl); return typeDecls; } /// /// Emitter-specific validation: check if there exist entity containers and /// entity sets that have the same name but differ in case /// protected override void Validate() { base.Validate(); Generator.VerifyLanguageCaseSensitiveCompatibilityForEntitySet(Item); VerifyEntityTypeAndSetAccessibilityCompatability(); } ////// Verify that Entity Set and Type have compatible accessibilty. /// They are compatible if the generated code will compile. /// private void VerifyEntityTypeAndSetAccessibilityCompatability() { foreach (EntitySetBase entitySetBase in Item.BaseEntitySets) { if (Helper.IsEntitySet(entitySetBase)) { EntitySet set = (EntitySet)entitySetBase; if (!AreTypeAndSetAccessCompatible(GetEntityTypeAccessibility(set.ElementType), GetEntitySetPropertyAccessibility(set))) { Generator.AddError( Strings.EntityTypeAndSetAccessibilityConflict( set.ElementType.Name, GetAccessibilityCsdlStringFromMemberAttribute(GetEntityTypeAccessibility(set.ElementType)), set.Name, GetAccessibilityCsdlStringFromMemberAttribute(GetEntitySetPropertyAccessibility(set))), ModelBuilderErrorCode.EntityTypeAndSetAccessibilityConflict, EdmSchemaErrorSeverity.Error); } } } } ////// Tells whether Entity Type's specified accessibility and Entity Set Property's specified Accessibility will work together (compile) when codegen'd. /// False if (Type is internal and Set's Property is Public OR, type is internal and Set's property is protected). /// True otherwise /// private bool AreTypeAndSetAccessCompatible(MemberAttributes typeAccess, MemberAttributes setAccess) { return !(typeAccess == MemberAttributes.Assembly && (setAccess == MemberAttributes.Public || setAccess == MemberAttributes.Family)); } ////// Creates the necessary constructors for the entity container. /// private void CreateConstructors(CodeTypeDeclaration typeDecl, bool setupTypeMapper, bool hasInheritance) { // Constructor that takes a uri // // public ctor(System.Uri serviceRoot) // : base(serviceRoot) // { // this.OnContextCreated(); // } CodeConstructor connectionWorkspaceCtor = new CodeConstructor(); connectionWorkspaceCtor.Attributes = MemberAttributes.Public; CodeParameterDeclarationExpression connectionParam = new CodeParameterDeclarationExpression(TypeReference.FromString("System.Uri", true), "serviceRoot"); connectionWorkspaceCtor.Parameters.Add(connectionParam); connectionWorkspaceCtor.BaseConstructorArgs.Add(new CodeArgumentReferenceExpression(connectionParam.Name)); CommentEmitter.EmitSummaryComments(Strings.CtorSummaryComment(Item.Name), connectionWorkspaceCtor.Comments); // If we have an externally provided namespage (e.g. from Visual Studio), we need to // inject a type-mapper because type names won't match between client and server if (setupTypeMapper || hasInheritance) { connectionWorkspaceCtor.Statements.Add( new CodeAssignStatement( new CodeFieldReferenceExpression(ThisRef, "ResolveName"), new CodeDelegateCreateExpression( TypeReference.ForType(typeof(Func<,>), TypeReference.ForType(typeof(Type)), TypeReference.ForType(typeof(String))), ThisRef, "ResolveNameFromType" ) ) ); } if (setupTypeMapper) { connectionWorkspaceCtor.Statements.Add( new CodeAssignStatement( new CodeFieldReferenceExpression(ThisRef, "ResolveType"), new CodeDelegateCreateExpression( TypeReference.ForType(typeof(Func<,>), TypeReference.ForType(typeof(String)), TypeReference.ForType(typeof(Type))), ThisRef, "ResolveTypeFromName" ) ) ); } connectionWorkspaceCtor.Statements.Add(OnContextCreatedCodeMethodInvokeExpression()); typeDecl.Members.Add(connectionWorkspaceCtor); } ////// Adds the OnContextCreated partial method for the entity container. /// private void CreateContextPartialMethods(CodeTypeDeclaration typeDecl) { CodeMemberMethod onContextCreatedPartialMethod = new CodeMemberMethod(); onContextCreatedPartialMethod.Name = _onContextCreatedString; onContextCreatedPartialMethod.ReturnType = new CodeTypeReference(typeof(void)); onContextCreatedPartialMethod.Attributes = MemberAttributes.Abstract | MemberAttributes.Public; typeDecl.Members.Add(onContextCreatedPartialMethod); Generator.FixUps.Add(new FixUp(Item.Name + "." + _onContextCreatedString, FixUpType.MarkAbstractMethodAsPartial)); } private void CreateTypeMappingMethods(CodeTypeDeclaration typeDecl, bool needTypeMapper, bool hasInheritance) { // Special case to compensate for VB's "root namespace" feature. if (this.Generator.Language == LanguageOption.GenerateVBCode) { AddRootNamespaceField(typeDecl); } CodeExpression comparisonExpression = new CodePropertyReferenceExpression( new CodeTypeReferenceExpression(TypeReference.ForType(typeof(StringComparison))), Enum.GetName(typeof(StringComparison), this.Generator.LanguageAppropriateStringComparer)); if (needTypeMapper) { CodeMemberMethod resolveTypeFromName = new CodeMemberMethod(); resolveTypeFromName.Name = "ResolveTypeFromName"; resolveTypeFromName.Attributes = MemberAttributes.Final | MemberAttributes.Family; resolveTypeFromName.Parameters.Add(new CodeParameterDeclarationExpression(TypeReference.ForType(typeof(string)), "typeName")); resolveTypeFromName.ReturnType = TypeReference.ForType(typeof(Type)); CommentEmitter.EmitSummaryComments(Strings.TypeMapperDescription, resolveTypeFromName.Comments); // NOTE: since multiple namespaces can have the same prefix and match the namespace // prefix condition, it's important that the prefix check is done is prefix-length // order, starting with the longest prefix. var pairs = this.Generator.NamespaceMap.OrderByDescending(p => p.Key.Length).ThenBy(p => p.Key); foreach (var pair in pairs) { // Assuming pair.Key is "abc" and pair.Value is "def" and len(def)=3, generate: // if (typeName.StartsWith("abc", StringComparison.Ordinal)) // return this.GetType().Assembly.GetType(string.Concat("def", typeName.Substring(3)), true) resolveTypeFromName.Statements.Add( new CodeConditionStatement( new CodeMethodInvokeExpression( new CodeVariableReferenceExpression("typeName"), "StartsWith", new CodePrimitiveExpression(pair.Key), comparisonExpression ), new CodeMethodReturnStatement( new CodeMethodInvokeExpression( new CodePropertyReferenceExpression( new CodeMethodInvokeExpression( ThisRef, "GetType" ), "Assembly" ), "GetType", new CodeMethodInvokeExpression( new CodeTypeReferenceExpression(TypeReference.ForType(typeof(string))), "Concat", this.LanguageSpecificNamespace(pair.Value), new CodeMethodInvokeExpression( new CodeVariableReferenceExpression("typeName"), "Substring", new CodePrimitiveExpression(pair.Key.Length) ) ), new CodePrimitiveExpression(true) // This overload doesn't exist in Silverlight //new CodePrimitiveExpression(!Generator.IsLanguageCaseSensitive) ) ) ) ); } resolveTypeFromName.Statements.Add( new CodeMethodReturnStatement( new CodePrimitiveExpression(null))); typeDecl.Members.Add(resolveTypeFromName); } CodeMemberMethod resolveNameFromType = new CodeMemberMethod(); resolveNameFromType.Name = "ResolveNameFromType"; resolveNameFromType.Attributes = MemberAttributes.Final | MemberAttributes.Family; resolveNameFromType.Parameters.Add(new CodeParameterDeclarationExpression(TypeReference.ForType(typeof(Type)), "clientType")); resolveNameFromType.ReturnType = TypeReference.ForType(typeof(String)); CommentEmitter.EmitSummaryComments(Strings.TypeMapperDescription, resolveNameFromType.Comments); // NOTE: in this case order also matters, but the length of the CLR // namespace is what needs to be considered. var reversePairs = Generator.NamespaceMap.OrderByDescending(p => p.Value.Length).ThenBy(p => p.Key); foreach (var pair in reversePairs) { // Assuming pair.Key is "abc" and pair.Value is "def", generate: // if (t.Namespace.Equals("def", StringComparison.Ordinal)) return string.Concat("abc.", t.Name); resolveNameFromType.Statements.Add( new CodeConditionStatement( new CodeMethodInvokeExpression( new CodePropertyReferenceExpression( new CodeVariableReferenceExpression("clientType"), "Namespace" ), "Equals", this.LanguageSpecificNamespace(pair.Value), comparisonExpression ), new CodeMethodReturnStatement( new CodeMethodInvokeExpression( new CodeTypeReferenceExpression(TypeReference.ForType(typeof(string))), "Concat", new CodePrimitiveExpression(pair.Key + "."), new CodePropertyReferenceExpression( new CodeVariableReferenceExpression("clientType"), "Name" ) ) ) ) ); } if (hasInheritance) { CodeExpression clientTypeFullName = new CodePropertyReferenceExpression( new CodeVariableReferenceExpression("clientType"), "FullName"); if (this.Generator.Language == LanguageOption.GenerateVBCode) { // return clientType.FullName.Substring(ROOTNAMESPACE.Length); resolveNameFromType.Statements.Add( new CodeMethodReturnStatement( new CodeMethodInvokeExpression( clientTypeFullName, "Substring", new CodePropertyReferenceExpression( new CodeVariableReferenceExpression("ROOTNAMESPACE"), "Length" ) ) ) ); } else { // return clientType.FullName; resolveNameFromType.Statements.Add(new CodeMethodReturnStatement(clientTypeFullName)); } } else { resolveNameFromType.Statements.Add( new CodeMethodReturnStatement( NullExpression ) ); } typeDecl.Members.Add(resolveNameFromType); } private void AddRootNamespaceField(CodeTypeDeclaration typeDecl) { // Add this field (VB declaration), where known client type name is ClientNS.BikesEntities // ROOTNAMESPACE = GetType(ClientNS.BikesEntities).Namespace.Remove(GetType(ClientNS.BikesEntities).Namespace.LastIndexOf("ClientNS")) EntityContainer container = (EntityContainer)this.Item; string containerNamespace = Generator.GetClientTypeNamespace(this.Generator.GetContainerNamespace(container)); // VB-ism: if namespace and type names are the same (Blah.Blah), GetType(Blah.Blah) fails... string vbScopedcontainerName = (string.IsNullOrEmpty(containerNamespace) || container.Name.Equals(containerNamespace, StringComparison.OrdinalIgnoreCase)) ? container.Name : (containerNamespace + "." + container.Name); CodeExpression namespaceAccess = new CodePropertyReferenceExpression( new CodeTypeOfExpression(vbScopedcontainerName), "Namespace"); CodeMemberField rootNamespaceField = new CodeMemberField( TypeReference.ForType(typeof(string)), "ROOTNAMESPACE"); rootNamespaceField.Attributes = MemberAttributes.Static | MemberAttributes.Private; rootNamespaceField.InitExpression = new CodeMethodInvokeExpression( namespaceAccess, "Remove", new CodeMethodInvokeExpression( namespaceAccess, "LastIndexOf", new CodePrimitiveExpression(containerNamespace))); typeDecl.Members.Add(rootNamespaceField); } private CodeExpression LanguageSpecificNamespace(string ns) { if (this.Generator.Language == LanguageOption.GenerateVBCode) { return new CodeMethodInvokeExpression( new CodeTypeReferenceExpression(TypeReference.ForType(typeof(string))), "Concat", new CodeVariableReferenceExpression("ROOTNAMESPACE"), new CodePrimitiveExpression(ns)); } else { return new CodePrimitiveExpression(ns); } } private CodeMemberField CreateEntitySetField(EntitySet set) { Debug.Assert(set != null, "Field is Null"); // trying to get // // private ObjectQuery_Customers = null; CodeMemberField codeField = new CodeMemberField(); codeField.Attributes = MemberAttributes.Final | MemberAttributes.Private; codeField.Name = Utils.FieldNameFromPropName(set.Name); CodeTypeReference genericParameter = Generator.GetLeastPossibleQualifiedTypeReference(set.ElementType); codeField.Type = TypeReference.AdoFrameworkGenericClass("DataServiceQuery", genericParameter); return codeField; } private CodeMemberProperty CreateEntitySetProperty(EntitySet set) { Debug.Assert(set != null, "Property is Null"); // trying to get // // [System.ComponentModel.Browsable(false)] // public ObjectQuery Customers // { // get // { // if ((this._Customers == null)) // { // this._Customers = base.CreateQuery ("[Customers]"); // } // return this._Customers; // } // } CodeMemberProperty codeProperty = new CodeMemberProperty(); codeProperty.Attributes = MemberAttributes.Final | GetEntitySetPropertyAccessibility(set); codeProperty.Name = set.Name; codeProperty.HasGet = true; codeProperty.HasSet = false; // SQLBUDT 598300: property to get query hides a property on base Context? if (null != TypeReference.ObjectContextBaseClassType.GetProperty(set.Name)) { codeProperty.Attributes |= MemberAttributes.New; } AttributeEmitter.AddBrowsableAttribute(codeProperty); CodeTypeReference genericParameter = Generator.GetLeastPossibleQualifiedTypeReference(set.ElementType); codeProperty.Type = TypeReference.AdoFrameworkGenericClass("DataServiceQuery", genericParameter); string fieldName = Utils.FieldNameFromPropName(set.Name); // raise the PropertyGenerated event before proceeding further PropertyGeneratedEventArgs eventArgs = new PropertyGeneratedEventArgs(set, fieldName, codeProperty.Type); Generator.RaisePropertyGeneratedEvent(eventArgs); if (eventArgs.ReturnType == null || !eventArgs.ReturnType.Equals(codeProperty.Type)) { throw EDesignUtil.InvalidOperation(Strings.CannotChangePropertyReturnType(set.Name, Item.Name)); } List additionalAttributes = eventArgs.AdditionalAttributes; if (additionalAttributes != null && additionalAttributes.Count > 0) { try { codeProperty.CustomAttributes.AddRange(additionalAttributes.ToArray()); } catch (ArgumentNullException e) { Generator.AddError(Strings.InvalidAttributeSuppliedForProperty(Item.Name), ModelBuilderErrorCode.InvalidAttributeSuppliedForProperty, EdmSchemaErrorSeverity.Error, e); } } // we need to insert user-specified code before other/existing code, including // the return statement List additionalGetStatements = eventArgs.AdditionalGetStatements; if (additionalGetStatements != null && additionalGetStatements.Count > 0) { try { codeProperty.GetStatements.AddRange(additionalGetStatements.ToArray()); } catch (ArgumentNullException e) { Generator.AddError(Strings.InvalidGetStatementSuppliedForProperty(Item.Name), ModelBuilderErrorCode.InvalidGetStatementSuppliedForProperty, EdmSchemaErrorSeverity.Error, e); } } codeProperty.GetStatements.Add( new CodeConditionStatement( EmitExpressionEqualsNull(new CodeFieldReferenceExpression(ThisRef, fieldName)), new CodeAssignStatement( new CodeFieldReferenceExpression(ThisRef, fieldName), new CodeMethodInvokeExpression( new CodeMethodReferenceExpression( new CodeBaseReferenceExpression(), "CreateQuery", new CodeTypeReference[] { genericParameter } ), new CodePrimitiveExpression(set.Name) ) ) ) ); codeProperty.GetStatements.Add( new CodeMethodReturnStatement( new CodeFieldReferenceExpression( ThisRef, fieldName ) ) ); // property summary CommentEmitter.EmitSummaryComments(set, codeProperty.Comments); return codeProperty; } /// /// Create an AddTo-EntitysetName methiod for each entityset in the context. /// /// EntityContainerEntitySet that we will go over to get the existing entitysets. ///Method definition private CodeMemberMethod CreateEntitySetAddObjectProperty(EntitySet set) { Debug.Assert(set != null, "Property is Null"); // trying to get // // public void AddToCustomer(Customer customer) // { // base.AddObject("Customer", customer); // } CodeMemberMethod codeMethod = new CodeMemberMethod(); codeMethod.Attributes = MemberAttributes.Final | GetEntityTypeAccessibility(set.ElementType); codeMethod.Name = ("AddTo" + set.Name); CodeParameterDeclarationExpression parameter = new CodeParameterDeclarationExpression(); parameter.Type = Generator.GetLeastPossibleQualifiedTypeReference(set.ElementType); parameter.Name = Utils.CamelCase(set.ElementType.Name); parameter.Name = Utils.SetSpecialCaseForFxCopOnPropertyName(parameter.Name); codeMethod.Parameters.Add(parameter); codeMethod.ReturnType = new CodeTypeReference(typeof(void)); codeMethod.Statements.Add( new CodeMethodInvokeExpression( new CodeBaseReferenceExpression(), "AddObject", new CodePrimitiveExpression(set.Name), new CodeFieldReferenceExpression(null, parameter.Name) ) ); // method summary CommentEmitter.EmitSummaryComments(set, codeMethod.Comments); return codeMethod; } ////// return a code expression for invoking OnContextCreated partial method /// private CodeMethodInvokeExpression OnContextCreatedCodeMethodInvokeExpression() { return (new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), _onContextCreatedString, new CodeExpression[] { })); } ////// Returns the type specific SchemaElement /// private new EntityContainer Item { get { return base.Item as EntityContainer; } } #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.Collections.Generic; using System.Data.Services.Design; using System.Data.Services.Design.Common; using System.Data.Metadata.Edm; using System.Data.Objects; using System.Diagnostics; using System.Linq; namespace System.Data.EntityModel.Emitters { ////// This class is responsible for emiting the code for the EntityContainer schema element /// internal sealed class EntityContainerEmitter : SchemaTypeEmitter { #region Fields private const string _onContextCreatedString = "OnContextCreated"; #endregion #region Constructors ////// /// /// /// public EntityContainerEmitter(ClientApiGenerator generator, EntityContainer entityContainer) : base(generator, entityContainer) { } #endregion #region Properties, Methods, Events & Delegates ////// Creates the CodeTypeDeclarations necessary to generate the code for the EntityContainer schema element /// ///public override CodeTypeDeclarationCollection EmitApiClass() { Validate(); // emitter-specific validation // declare the new class // public partial class LOBScenario : ObjectContext CodeTypeDeclaration typeDecl = new CodeTypeDeclaration(Item.Name); typeDecl.IsPartial = true; // raise the TypeGenerated event CodeTypeReference objectContextTypeRef = TypeReference.ObjectContext; TypeGeneratedEventArgs eventArgs = new TypeGeneratedEventArgs(Item, objectContextTypeRef); Generator.RaiseTypeGeneratedEvent(eventArgs); if (eventArgs.BaseType != null && !eventArgs.BaseType.Equals(objectContextTypeRef)) { typeDecl.BaseTypes.Add(eventArgs.BaseType); } else { typeDecl.BaseTypes.Add(TypeReference.ObjectContext); } AddInterfaces(Item.Name, typeDecl, eventArgs.AdditionalInterfaces); CommentEmitter.EmitSummaryComments(Item, typeDecl.Comments); EmitTypeAttributes(Item.Name, typeDecl, eventArgs.AdditionalAttributes); bool needTypeMapper = (0 < this.Generator.NamespaceMap.Count); var q = from a in this.Generator.EdmItemCollection.GetItems () where (a.BaseType != null) && (a.BuiltInTypeKind == BuiltInTypeKind.ComplexType || a.BuiltInTypeKind == BuiltInTypeKind.EntityType) select a; bool hasInheritance = (null != q.FirstOrDefault()); CreateConstructors(typeDecl, needTypeMapper, hasInheritance); // adding partial OnContextCreated method CreateContextPartialMethods(typeDecl); if (needTypeMapper || hasInheritance) { CreateTypeMappingMethods(typeDecl, needTypeMapper, hasInheritance); } foreach (EntitySetBase entitySetBase in Item.BaseEntitySets) { if (Helper.IsEntitySet(entitySetBase)) { EntitySet set = (EntitySet)entitySetBase; CodeMemberProperty codeProperty = CreateEntitySetProperty(set); typeDecl.Members.Add(codeProperty); CodeMemberField codeField = CreateEntitySetField(set); typeDecl.Members.Add(codeField); } } foreach (EntitySetBase entitySetBase in Item.BaseEntitySets) { if (Helper.IsEntitySet(entitySetBase)) { EntitySet set = (EntitySet)entitySetBase; CodeMemberMethod codeProperty = CreateEntitySetAddObjectProperty(set); typeDecl.Members.Add(codeProperty); } } // additional members, if provided by the event subscriber AddMembers(Item.Name, typeDecl, eventArgs.AdditionalMembers); CodeTypeDeclarationCollection typeDecls = new CodeTypeDeclarationCollection(); typeDecls.Add(typeDecl); return typeDecls; } /// /// Emitter-specific validation: check if there exist entity containers and /// entity sets that have the same name but differ in case /// protected override void Validate() { base.Validate(); Generator.VerifyLanguageCaseSensitiveCompatibilityForEntitySet(Item); VerifyEntityTypeAndSetAccessibilityCompatability(); } ////// Verify that Entity Set and Type have compatible accessibilty. /// They are compatible if the generated code will compile. /// private void VerifyEntityTypeAndSetAccessibilityCompatability() { foreach (EntitySetBase entitySetBase in Item.BaseEntitySets) { if (Helper.IsEntitySet(entitySetBase)) { EntitySet set = (EntitySet)entitySetBase; if (!AreTypeAndSetAccessCompatible(GetEntityTypeAccessibility(set.ElementType), GetEntitySetPropertyAccessibility(set))) { Generator.AddError( Strings.EntityTypeAndSetAccessibilityConflict( set.ElementType.Name, GetAccessibilityCsdlStringFromMemberAttribute(GetEntityTypeAccessibility(set.ElementType)), set.Name, GetAccessibilityCsdlStringFromMemberAttribute(GetEntitySetPropertyAccessibility(set))), ModelBuilderErrorCode.EntityTypeAndSetAccessibilityConflict, EdmSchemaErrorSeverity.Error); } } } } ////// Tells whether Entity Type's specified accessibility and Entity Set Property's specified Accessibility will work together (compile) when codegen'd. /// False if (Type is internal and Set's Property is Public OR, type is internal and Set's property is protected). /// True otherwise /// private bool AreTypeAndSetAccessCompatible(MemberAttributes typeAccess, MemberAttributes setAccess) { return !(typeAccess == MemberAttributes.Assembly && (setAccess == MemberAttributes.Public || setAccess == MemberAttributes.Family)); } ////// Creates the necessary constructors for the entity container. /// private void CreateConstructors(CodeTypeDeclaration typeDecl, bool setupTypeMapper, bool hasInheritance) { // Constructor that takes a uri // // public ctor(System.Uri serviceRoot) // : base(serviceRoot) // { // this.OnContextCreated(); // } CodeConstructor connectionWorkspaceCtor = new CodeConstructor(); connectionWorkspaceCtor.Attributes = MemberAttributes.Public; CodeParameterDeclarationExpression connectionParam = new CodeParameterDeclarationExpression(TypeReference.FromString("System.Uri", true), "serviceRoot"); connectionWorkspaceCtor.Parameters.Add(connectionParam); connectionWorkspaceCtor.BaseConstructorArgs.Add(new CodeArgumentReferenceExpression(connectionParam.Name)); CommentEmitter.EmitSummaryComments(Strings.CtorSummaryComment(Item.Name), connectionWorkspaceCtor.Comments); // If we have an externally provided namespage (e.g. from Visual Studio), we need to // inject a type-mapper because type names won't match between client and server if (setupTypeMapper || hasInheritance) { connectionWorkspaceCtor.Statements.Add( new CodeAssignStatement( new CodeFieldReferenceExpression(ThisRef, "ResolveName"), new CodeDelegateCreateExpression( TypeReference.ForType(typeof(Func<,>), TypeReference.ForType(typeof(Type)), TypeReference.ForType(typeof(String))), ThisRef, "ResolveNameFromType" ) ) ); } if (setupTypeMapper) { connectionWorkspaceCtor.Statements.Add( new CodeAssignStatement( new CodeFieldReferenceExpression(ThisRef, "ResolveType"), new CodeDelegateCreateExpression( TypeReference.ForType(typeof(Func<,>), TypeReference.ForType(typeof(String)), TypeReference.ForType(typeof(Type))), ThisRef, "ResolveTypeFromName" ) ) ); } connectionWorkspaceCtor.Statements.Add(OnContextCreatedCodeMethodInvokeExpression()); typeDecl.Members.Add(connectionWorkspaceCtor); } ////// Adds the OnContextCreated partial method for the entity container. /// private void CreateContextPartialMethods(CodeTypeDeclaration typeDecl) { CodeMemberMethod onContextCreatedPartialMethod = new CodeMemberMethod(); onContextCreatedPartialMethod.Name = _onContextCreatedString; onContextCreatedPartialMethod.ReturnType = new CodeTypeReference(typeof(void)); onContextCreatedPartialMethod.Attributes = MemberAttributes.Abstract | MemberAttributes.Public; typeDecl.Members.Add(onContextCreatedPartialMethod); Generator.FixUps.Add(new FixUp(Item.Name + "." + _onContextCreatedString, FixUpType.MarkAbstractMethodAsPartial)); } private void CreateTypeMappingMethods(CodeTypeDeclaration typeDecl, bool needTypeMapper, bool hasInheritance) { // Special case to compensate for VB's "root namespace" feature. if (this.Generator.Language == LanguageOption.GenerateVBCode) { AddRootNamespaceField(typeDecl); } CodeExpression comparisonExpression = new CodePropertyReferenceExpression( new CodeTypeReferenceExpression(TypeReference.ForType(typeof(StringComparison))), Enum.GetName(typeof(StringComparison), this.Generator.LanguageAppropriateStringComparer)); if (needTypeMapper) { CodeMemberMethod resolveTypeFromName = new CodeMemberMethod(); resolveTypeFromName.Name = "ResolveTypeFromName"; resolveTypeFromName.Attributes = MemberAttributes.Final | MemberAttributes.Family; resolveTypeFromName.Parameters.Add(new CodeParameterDeclarationExpression(TypeReference.ForType(typeof(string)), "typeName")); resolveTypeFromName.ReturnType = TypeReference.ForType(typeof(Type)); CommentEmitter.EmitSummaryComments(Strings.TypeMapperDescription, resolveTypeFromName.Comments); // NOTE: since multiple namespaces can have the same prefix and match the namespace // prefix condition, it's important that the prefix check is done is prefix-length // order, starting with the longest prefix. var pairs = this.Generator.NamespaceMap.OrderByDescending(p => p.Key.Length).ThenBy(p => p.Key); foreach (var pair in pairs) { // Assuming pair.Key is "abc" and pair.Value is "def" and len(def)=3, generate: // if (typeName.StartsWith("abc", StringComparison.Ordinal)) // return this.GetType().Assembly.GetType(string.Concat("def", typeName.Substring(3)), true) resolveTypeFromName.Statements.Add( new CodeConditionStatement( new CodeMethodInvokeExpression( new CodeVariableReferenceExpression("typeName"), "StartsWith", new CodePrimitiveExpression(pair.Key), comparisonExpression ), new CodeMethodReturnStatement( new CodeMethodInvokeExpression( new CodePropertyReferenceExpression( new CodeMethodInvokeExpression( ThisRef, "GetType" ), "Assembly" ), "GetType", new CodeMethodInvokeExpression( new CodeTypeReferenceExpression(TypeReference.ForType(typeof(string))), "Concat", this.LanguageSpecificNamespace(pair.Value), new CodeMethodInvokeExpression( new CodeVariableReferenceExpression("typeName"), "Substring", new CodePrimitiveExpression(pair.Key.Length) ) ), new CodePrimitiveExpression(true) // This overload doesn't exist in Silverlight //new CodePrimitiveExpression(!Generator.IsLanguageCaseSensitive) ) ) ) ); } resolveTypeFromName.Statements.Add( new CodeMethodReturnStatement( new CodePrimitiveExpression(null))); typeDecl.Members.Add(resolveTypeFromName); } CodeMemberMethod resolveNameFromType = new CodeMemberMethod(); resolveNameFromType.Name = "ResolveNameFromType"; resolveNameFromType.Attributes = MemberAttributes.Final | MemberAttributes.Family; resolveNameFromType.Parameters.Add(new CodeParameterDeclarationExpression(TypeReference.ForType(typeof(Type)), "clientType")); resolveNameFromType.ReturnType = TypeReference.ForType(typeof(String)); CommentEmitter.EmitSummaryComments(Strings.TypeMapperDescription, resolveNameFromType.Comments); // NOTE: in this case order also matters, but the length of the CLR // namespace is what needs to be considered. var reversePairs = Generator.NamespaceMap.OrderByDescending(p => p.Value.Length).ThenBy(p => p.Key); foreach (var pair in reversePairs) { // Assuming pair.Key is "abc" and pair.Value is "def", generate: // if (t.Namespace.Equals("def", StringComparison.Ordinal)) return string.Concat("abc.", t.Name); resolveNameFromType.Statements.Add( new CodeConditionStatement( new CodeMethodInvokeExpression( new CodePropertyReferenceExpression( new CodeVariableReferenceExpression("clientType"), "Namespace" ), "Equals", this.LanguageSpecificNamespace(pair.Value), comparisonExpression ), new CodeMethodReturnStatement( new CodeMethodInvokeExpression( new CodeTypeReferenceExpression(TypeReference.ForType(typeof(string))), "Concat", new CodePrimitiveExpression(pair.Key + "."), new CodePropertyReferenceExpression( new CodeVariableReferenceExpression("clientType"), "Name" ) ) ) ) ); } if (hasInheritance) { CodeExpression clientTypeFullName = new CodePropertyReferenceExpression( new CodeVariableReferenceExpression("clientType"), "FullName"); if (this.Generator.Language == LanguageOption.GenerateVBCode) { // return clientType.FullName.Substring(ROOTNAMESPACE.Length); resolveNameFromType.Statements.Add( new CodeMethodReturnStatement( new CodeMethodInvokeExpression( clientTypeFullName, "Substring", new CodePropertyReferenceExpression( new CodeVariableReferenceExpression("ROOTNAMESPACE"), "Length" ) ) ) ); } else { // return clientType.FullName; resolveNameFromType.Statements.Add(new CodeMethodReturnStatement(clientTypeFullName)); } } else { resolveNameFromType.Statements.Add( new CodeMethodReturnStatement( NullExpression ) ); } typeDecl.Members.Add(resolveNameFromType); } private void AddRootNamespaceField(CodeTypeDeclaration typeDecl) { // Add this field (VB declaration), where known client type name is ClientNS.BikesEntities // ROOTNAMESPACE = GetType(ClientNS.BikesEntities).Namespace.Remove(GetType(ClientNS.BikesEntities).Namespace.LastIndexOf("ClientNS")) EntityContainer container = (EntityContainer)this.Item; string containerNamespace = Generator.GetClientTypeNamespace(this.Generator.GetContainerNamespace(container)); // VB-ism: if namespace and type names are the same (Blah.Blah), GetType(Blah.Blah) fails... string vbScopedcontainerName = (string.IsNullOrEmpty(containerNamespace) || container.Name.Equals(containerNamespace, StringComparison.OrdinalIgnoreCase)) ? container.Name : (containerNamespace + "." + container.Name); CodeExpression namespaceAccess = new CodePropertyReferenceExpression( new CodeTypeOfExpression(vbScopedcontainerName), "Namespace"); CodeMemberField rootNamespaceField = new CodeMemberField( TypeReference.ForType(typeof(string)), "ROOTNAMESPACE"); rootNamespaceField.Attributes = MemberAttributes.Static | MemberAttributes.Private; rootNamespaceField.InitExpression = new CodeMethodInvokeExpression( namespaceAccess, "Remove", new CodeMethodInvokeExpression( namespaceAccess, "LastIndexOf", new CodePrimitiveExpression(containerNamespace))); typeDecl.Members.Add(rootNamespaceField); } private CodeExpression LanguageSpecificNamespace(string ns) { if (this.Generator.Language == LanguageOption.GenerateVBCode) { return new CodeMethodInvokeExpression( new CodeTypeReferenceExpression(TypeReference.ForType(typeof(string))), "Concat", new CodeVariableReferenceExpression("ROOTNAMESPACE"), new CodePrimitiveExpression(ns)); } else { return new CodePrimitiveExpression(ns); } } private CodeMemberField CreateEntitySetField(EntitySet set) { Debug.Assert(set != null, "Field is Null"); // trying to get // // private ObjectQuery_Customers = null; CodeMemberField codeField = new CodeMemberField(); codeField.Attributes = MemberAttributes.Final | MemberAttributes.Private; codeField.Name = Utils.FieldNameFromPropName(set.Name); CodeTypeReference genericParameter = Generator.GetLeastPossibleQualifiedTypeReference(set.ElementType); codeField.Type = TypeReference.AdoFrameworkGenericClass("DataServiceQuery", genericParameter); return codeField; } private CodeMemberProperty CreateEntitySetProperty(EntitySet set) { Debug.Assert(set != null, "Property is Null"); // trying to get // // [System.ComponentModel.Browsable(false)] // public ObjectQuery Customers // { // get // { // if ((this._Customers == null)) // { // this._Customers = base.CreateQuery ("[Customers]"); // } // return this._Customers; // } // } CodeMemberProperty codeProperty = new CodeMemberProperty(); codeProperty.Attributes = MemberAttributes.Final | GetEntitySetPropertyAccessibility(set); codeProperty.Name = set.Name; codeProperty.HasGet = true; codeProperty.HasSet = false; // SQLBUDT 598300: property to get query hides a property on base Context? if (null != TypeReference.ObjectContextBaseClassType.GetProperty(set.Name)) { codeProperty.Attributes |= MemberAttributes.New; } AttributeEmitter.AddBrowsableAttribute(codeProperty); CodeTypeReference genericParameter = Generator.GetLeastPossibleQualifiedTypeReference(set.ElementType); codeProperty.Type = TypeReference.AdoFrameworkGenericClass("DataServiceQuery", genericParameter); string fieldName = Utils.FieldNameFromPropName(set.Name); // raise the PropertyGenerated event before proceeding further PropertyGeneratedEventArgs eventArgs = new PropertyGeneratedEventArgs(set, fieldName, codeProperty.Type); Generator.RaisePropertyGeneratedEvent(eventArgs); if (eventArgs.ReturnType == null || !eventArgs.ReturnType.Equals(codeProperty.Type)) { throw EDesignUtil.InvalidOperation(Strings.CannotChangePropertyReturnType(set.Name, Item.Name)); } List additionalAttributes = eventArgs.AdditionalAttributes; if (additionalAttributes != null && additionalAttributes.Count > 0) { try { codeProperty.CustomAttributes.AddRange(additionalAttributes.ToArray()); } catch (ArgumentNullException e) { Generator.AddError(Strings.InvalidAttributeSuppliedForProperty(Item.Name), ModelBuilderErrorCode.InvalidAttributeSuppliedForProperty, EdmSchemaErrorSeverity.Error, e); } } // we need to insert user-specified code before other/existing code, including // the return statement List additionalGetStatements = eventArgs.AdditionalGetStatements; if (additionalGetStatements != null && additionalGetStatements.Count > 0) { try { codeProperty.GetStatements.AddRange(additionalGetStatements.ToArray()); } catch (ArgumentNullException e) { Generator.AddError(Strings.InvalidGetStatementSuppliedForProperty(Item.Name), ModelBuilderErrorCode.InvalidGetStatementSuppliedForProperty, EdmSchemaErrorSeverity.Error, e); } } codeProperty.GetStatements.Add( new CodeConditionStatement( EmitExpressionEqualsNull(new CodeFieldReferenceExpression(ThisRef, fieldName)), new CodeAssignStatement( new CodeFieldReferenceExpression(ThisRef, fieldName), new CodeMethodInvokeExpression( new CodeMethodReferenceExpression( new CodeBaseReferenceExpression(), "CreateQuery", new CodeTypeReference[] { genericParameter } ), new CodePrimitiveExpression(set.Name) ) ) ) ); codeProperty.GetStatements.Add( new CodeMethodReturnStatement( new CodeFieldReferenceExpression( ThisRef, fieldName ) ) ); // property summary CommentEmitter.EmitSummaryComments(set, codeProperty.Comments); return codeProperty; } /// /// Create an AddTo-EntitysetName methiod for each entityset in the context. /// /// EntityContainerEntitySet that we will go over to get the existing entitysets. ///Method definition private CodeMemberMethod CreateEntitySetAddObjectProperty(EntitySet set) { Debug.Assert(set != null, "Property is Null"); // trying to get // // public void AddToCustomer(Customer customer) // { // base.AddObject("Customer", customer); // } CodeMemberMethod codeMethod = new CodeMemberMethod(); codeMethod.Attributes = MemberAttributes.Final | GetEntityTypeAccessibility(set.ElementType); codeMethod.Name = ("AddTo" + set.Name); CodeParameterDeclarationExpression parameter = new CodeParameterDeclarationExpression(); parameter.Type = Generator.GetLeastPossibleQualifiedTypeReference(set.ElementType); parameter.Name = Utils.CamelCase(set.ElementType.Name); parameter.Name = Utils.SetSpecialCaseForFxCopOnPropertyName(parameter.Name); codeMethod.Parameters.Add(parameter); codeMethod.ReturnType = new CodeTypeReference(typeof(void)); codeMethod.Statements.Add( new CodeMethodInvokeExpression( new CodeBaseReferenceExpression(), "AddObject", new CodePrimitiveExpression(set.Name), new CodeFieldReferenceExpression(null, parameter.Name) ) ); // method summary CommentEmitter.EmitSummaryComments(set, codeMethod.Comments); return codeMethod; } ////// return a code expression for invoking OnContextCreated partial method /// private CodeMethodInvokeExpression OnContextCreatedCodeMethodInvokeExpression() { return (new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), _onContextCreatedString, new CodeExpression[] { })); } ////// Returns the type specific SchemaElement /// private new EntityContainer Item { get { return base.Item as EntityContainer; } } #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
- CellParagraph.cs
- PeerContact.cs
- WebPartMinimizeVerb.cs
- TextAnchor.cs
- FixedTextView.cs
- FactoryMaker.cs
- SocketElement.cs
- UrlAuthFailedErrorFormatter.cs
- CodeGotoStatement.cs
- WorkflowInstance.cs
- DictationGrammar.cs
- RadioButtonFlatAdapter.cs
- TextServicesManager.cs
- FileUtil.cs
- CompiledQuery.cs
- Debug.cs
- Inflater.cs
- selecteditemcollection.cs
- PackageFilter.cs
- OleDbRowUpdatingEvent.cs
- EnvelopedSignatureTransform.cs
- GenericXmlSecurityToken.cs
- sortedlist.cs
- XmlSchemaChoice.cs
- WasHttpModulesInstallComponent.cs
- WindowsIdentity.cs
- ControlCollection.cs
- TableFieldsEditor.cs
- ManipulationStartedEventArgs.cs
- ParseChildrenAsPropertiesAttribute.cs
- ServiceModelInstallComponent.cs
- CompModSwitches.cs
- TimeStampChecker.cs
- WebBrowserSiteBase.cs
- StorageFunctionMapping.cs
- PersonalizationEntry.cs
- DbParameterCollectionHelper.cs
- RelationshipWrapper.cs
- EncryptedReference.cs
- AsyncDataRequest.cs
- Int32Rect.cs
- ObjectReaderCompiler.cs
- SecurityHelper.cs
- ContentPresenter.cs
- XomlSerializationHelpers.cs
- ListenerUnsafeNativeMethods.cs
- InputLanguageCollection.cs
- NextPreviousPagerField.cs
- UserControl.cs
- ProfileGroupSettingsCollection.cs
- FontWeightConverter.cs
- TreeViewImageIndexConverter.cs
- EnumValidator.cs
- Visual3DCollection.cs
- TextElement.cs
- ConcatQueryOperator.cs
- Guid.cs
- SqlWriter.cs
- NativeMethods.cs
- VectorValueSerializer.cs
- OperationParameterInfoCollection.cs
- UriTemplateQueryValue.cs
- EntityViewGenerator.cs
- PrtTicket_Base.cs
- FamilyTypeface.cs
- ResXResourceSet.cs
- AuthenticationConfig.cs
- FontDifferentiator.cs
- WebPartConnectionsConnectVerb.cs
- ContractInstanceProvider.cs
- DocumentCollection.cs
- Operand.cs
- SizeChangedInfo.cs
- DataGridViewControlCollection.cs
- RadioButtonDesigner.cs
- _TLSstream.cs
- UnsafeNativeMethods.cs
- ByteStorage.cs
- NullableDecimalMinMaxAggregationOperator.cs
- ServiceDescription.cs
- QueryAccessibilityHelpEvent.cs
- ASCIIEncoding.cs
- Stylesheet.cs
- AnonymousIdentificationSection.cs
- XmlUtil.cs
- DataGridViewRowConverter.cs
- SchemaImporter.cs
- XamlBrushSerializer.cs
- Expression.cs
- MenuScrollingVisibilityConverter.cs
- ApplicationId.cs
- BooleanConverter.cs
- CodeDomConfigurationHandler.cs
- StoreContentChangedEventArgs.cs
- WebPartConnectVerb.cs
- ZipIOCentralDirectoryFileHeader.cs
- BamlVersionHeader.cs
- RelationshipDetailsCollection.cs
- NGCSerializationManagerAsync.cs
- TreeView.cs