Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / ndp / fx / src / DataWeb / Design / system / Data / EntityModel / Emitters / EntityContainerEmitter.cs / 4 / 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
- AppDomainShutdownMonitor.cs
- PublisherMembershipCondition.cs
- WindowsMenu.cs
- FtpWebResponse.cs
- SerializationStore.cs
- ListItemsCollectionEditor.cs
- ExpressionBinding.cs
- WindowsGraphics.cs
- ArgIterator.cs
- DataGridViewMethods.cs
- AssociationTypeEmitter.cs
- SignatureDescription.cs
- NodeInfo.cs
- DataGridViewRowHeightInfoPushedEventArgs.cs
- XmlSchemaExternal.cs
- entitydatasourceentitysetnameconverter.cs
- CqlBlock.cs
- Base64Encoder.cs
- WriteableOnDemandStream.cs
- TrustLevel.cs
- StreamGeometry.cs
- GZipDecoder.cs
- AspNetHostingPermission.cs
- ShaperBuffers.cs
- HtmlHistory.cs
- ImageConverter.cs
- ScrollPatternIdentifiers.cs
- SafeFileMappingHandle.cs
- XmlText.cs
- NameHandler.cs
- AssertFilter.cs
- DesignerVerb.cs
- SByte.cs
- OdbcEnvironmentHandle.cs
- SortedList.cs
- DefaultValidator.cs
- ErrorRuntimeConfig.cs
- MemberNameValidator.cs
- SystemGatewayIPAddressInformation.cs
- PropertyMap.cs
- PropertyCondition.cs
- IndependentlyAnimatedPropertyMetadata.cs
- TextRangeEditTables.cs
- ListBoxItemWrapperAutomationPeer.cs
- WebHeaderCollection.cs
- XmlBinaryReaderSession.cs
- TabControlCancelEvent.cs
- NamespaceEmitter.cs
- RowBinding.cs
- XmlComplianceUtil.cs
- RtfControlWordInfo.cs
- DocumentPage.cs
- SettingsBase.cs
- SqlClientPermission.cs
- ToolStripRenderer.cs
- BackgroundWorker.cs
- TargetConverter.cs
- UpdateManifestForBrowserApplication.cs
- DataBinder.cs
- TableRow.cs
- ProjectionPath.cs
- FileReservationCollection.cs
- TextBoxBase.cs
- PropertyKey.cs
- StorageFunctionMapping.cs
- ClientTargetCollection.cs
- AtomPub10CategoriesDocumentFormatter.cs
- Single.cs
- FixedPosition.cs
- MenuCommandService.cs
- Brush.cs
- RemoveStoryboard.cs
- GridErrorDlg.cs
- CssClassPropertyAttribute.cs
- BitmapSource.cs
- TextRenderer.cs
- WebPartPersonalization.cs
- DeviceFiltersSection.cs
- StringAnimationBase.cs
- DataControlField.cs
- WebExceptionStatus.cs
- IntSecurity.cs
- SqlCacheDependency.cs
- GestureRecognitionResult.cs
- Ticks.cs
- UInt16.cs
- HtmlCommandAdapter.cs
- FontDialog.cs
- Propagator.ExtentPlaceholderCreator.cs
- BufferModeSettings.cs
- LoginUtil.cs
- XmlArrayItemAttributes.cs
- UIElementParaClient.cs
- BindableTemplateBuilder.cs
- Range.cs
- WebPartEditorApplyVerb.cs
- HostedTransportConfigurationManager.cs
- CheckBoxList.cs
- Query.cs
- ValueChangedEventManager.cs