private CodeMemberProperty EmitPropertyDeclaration(MemberAttributes scope, CodeTypeReference propertyType, bool isVirtual, bool hidesBaseProperty) { Debug.Assert(GetAccessibilityRank(scope) >= 0, "scope should only be an accessibility attribute"); CodeMemberProperty memberProperty = new CodeMemberProperty(); memberProperty.Name = PropertyName; CommentEmitter.EmitSummaryComments(Item, memberProperty.Comments); memberProperty.Attributes = scope; if (!isVirtual) { memberProperty.Attributes |= MemberAttributes.Final; } if (hidesBaseProperty || AncestorClassDefinesName(memberProperty.Name)) { memberProperty.Attributes |= MemberAttributes.New; } memberProperty.Type = propertyType; return(memberProperty); }
private void Emit(Dictionary <string, string> usedClassName, string namespaceName, List <GlobalItem> items) { // it is a valid scenario for namespaceName to be empty //string namespaceName = Generator.SourceObjectNamespaceName; Generator.SourceEdmNamespaceName = namespaceName; // emit the namespace definition CodeNamespace codeNamespace = new CodeNamespace(namespaceName); // output some boiler plate comments string comments = Strings.NamespaceComments( System.IO.Path.GetFileName(_targetFilePath), DateTime.Now.ToString(System.Globalization.CultureInfo.CurrentCulture)); CommentEmitter.EmitComments(CommentEmitter.GetFormattedLines(comments, false), codeNamespace.Comments, false); CompileUnit.Namespaces.Add(codeNamespace); // Emit the classes in the schema foreach (GlobalItem element in items) { if (AddElementNameToCache(element, usedClassName)) { SchemaTypeEmitter emitter = CreateElementEmitter(element); CodeTypeDeclarationCollection typeDeclaration = emitter.EmitApiClass(); if (typeDeclaration.Count > 0) { codeNamespace.Types.AddRange(typeDeclaration); } } } Generator.SourceEdmNamespaceName = null; }
/// <summary> /// Creates the necessary constructors for the entity container. /// </summary> 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)); AttributeEmitter.AddGeneratedCodeAttribute(connectionWorkspaceCtor); 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); }
/// <summary> /// Creates the CodeTypeDeclarations necessary to generate the code /// </summary> public void Emit() { // it is a valid scenario for namespaceName to be empty string namespaceName = Generator.SourceObjectNamespaceName; // emit the namespace definition CodeNamespace codeNamespace = new CodeNamespace(namespaceName); // output some boiler plate comments string comments = Strings.NamespaceComments( System.IO.Path.GetFileName(_targetFilePath), DateTime.Now.ToString(System.Globalization.CultureInfo.CurrentCulture)); CommentEmitter.EmitComments(CommentEmitter.GetFormattedLines(comments, false), codeNamespace.Comments, false); CompileUnit.Namespaces.Add(codeNamespace); // Add the assembly attribute. CodeAttributeDeclaration assemblyAttribute; // SQLBUDT 505339: VB compiler fails if multiple assembly attributes exist in the same project. // This adds a GUID to the assembly attribute so that each generated file will have a unique EdmSchemaAttribute in VB. if (this.Generator.Language == System.Data.Entity.Design.LanguageOption.GenerateVBCode) //The GUID is only added in VB { assemblyAttribute = AttributeEmitter.EmitSimpleAttribute("System.Data.Objects.DataClasses.EdmSchemaAttribute", System.Guid.NewGuid().ToString()); } else { assemblyAttribute = AttributeEmitter.EmitSimpleAttribute("System.Data.Objects.DataClasses.EdmSchemaAttribute"); } CompileUnit.AssemblyCustomAttributes.Add(assemblyAttribute); Dictionary <string, string> usedClassName = new Dictionary <string, string>(StringComparer.Ordinal); // Emit the classes in the schema foreach (GlobalItem element in Generator.GetSourceTypes()) { Debug.Assert(!(element is EdmFunction), "Are you trying to emit functions now? If so add an emitter for it."); if (AddElementNameToCache(element, usedClassName)) { SchemaTypeEmitter emitter = CreateElementEmitter(element); CodeTypeDeclarationCollection typeDeclaration = emitter.EmitApiClass(); if (typeDeclaration.Count > 0) { codeNamespace.Types.AddRange(typeDeclaration); } } } }
/// <summary> /// /// </summary> /// <returns></returns> public override CodeTypeDeclarationCollection EmitApiClass() { Validate(); // emitter-specific validation CodeTypeReference baseType = this.GetBaseType(); // raise the TypeGenerated event TypeGeneratedEventArgs eventArgs = new TypeGeneratedEventArgs(Item, baseType); this.Generator.RaiseTypeGeneratedEvent(eventArgs); // public [abstract] partial class ClassName CodeTypeDeclaration typeDecl = new CodeTypeDeclaration(Item.Name); typeDecl.IsPartial = true; typeDecl.TypeAttributes = System.Reflection.TypeAttributes.Class; if (Item.Abstract) { typeDecl.TypeAttributes |= System.Reflection.TypeAttributes.Abstract; } SetTypeVisibility(typeDecl); EmitTypeAttributes(Item.Name, typeDecl, eventArgs.AdditionalAttributes); // : baseclass AssignBaseType(typeDecl, baseType, eventArgs.BaseType); AddInterfaces(Item.Name, typeDecl, eventArgs.AdditionalInterfaces); CommentEmitter.EmitSummaryComments(Item, typeDecl.Comments); // Since abstract types cannot be instantiated, skip the factory method for abstract types if ((typeDecl.TypeAttributes & System.Reflection.TypeAttributes.Abstract) == 0) { EmitFactoryMethod(typeDecl); } EmitProperties(typeDecl); // additional members, if provided by the event subscriber this.AddMembers(Item.Name, typeDecl, eventArgs.AdditionalMembers); CodeTypeDeclarationCollection typeDecls = new CodeTypeDeclarationCollection(); typeDecls.Add(typeDecl); return(typeDecls); }
/// <summary> /// Create an AddTo-EntitysetName methiod for each entityset in the context. /// </summary> /// <param name="set">EntityContainerEntitySet that we will go over to get the existing entitysets.</param> /// <returns> Method definition </returns> private CodeMemberMethod CreateEntitySetAddObjectMethod(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)); AttributeEmitter.AddGeneratedCodeAttribute(codeMethod); 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); }
/// <summary> /// Creates the CodeTypeDeclarations necessary to generate the code for the EntityContainer schema element /// </summary> /// <returns></returns> 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); CreateConstructors(typeDecl); // adding partial OnContextCreated method CreateContextPartialMethods(typeDecl); foreach (EntitySetBase entitySetBase in Item.BaseEntitySets) { if (MetadataUtil.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 (MetadataUtil.IsEntitySet(entitySetBase)) { EntitySet set = (EntitySet)entitySetBase; CodeMemberMethod codeProperty = CreateEntitySetAddObjectProperty(set); typeDecl.Members.Add(codeProperty); } } foreach (EdmFunction functionImport in Item.FunctionImports) { if (ShouldEmitFunctionImport(functionImport)) { CodeMemberMethod functionMethod = CreateFunctionImportStructuralTypeReaderMethod(functionImport); typeDecl.Members.Add(functionMethod); } } // additional members, if provided by the event subscriber AddMembers(Item.Name, typeDecl, eventArgs.AdditionalMembers); CodeTypeDeclarationCollection typeDecls = new CodeTypeDeclarationCollection(); typeDecls.Add(typeDecl); return(typeDecls); }
/// <summary> /// Create a method entry point for a function import yielding an entity reader. /// </summary> /// <param name="functionImport">SOM for function import; must not be null and must yield /// an entity reader.</param> /// <returns>Method definition.</returns> private CodeMemberMethod CreateFunctionImportStructuralTypeReaderMethod(EdmFunction functionImport) { // Trying to get: // ///// <summary> ///// Documentation ///// </summary> //public ObjectQueryResult<MyType> MyFunctionImport(Nullable<int> id, string foo) //{ // ObjectParameter idParameter; // if (id.HasValue) // { // idParameter = new ObjectParameter("id", id); // } // else // { // idParameter = new ObjectParameter("id", typeof(int)); // } // ObjectParameter fooParameter; // if (null != foo) // { // fooParameter = new ObjectParameter("foo", foo); // } // else // { // fooParameter = new ObjectParameter("foo", typeof(string)); // } // return base.ExecuteFunction<MyType>("MyFunctionImport", idParameter, fooParameter); //} Debug.Assert(null != functionImport); CodeMemberMethod method = new CodeMemberMethod(); Generator.AttributeEmitter.EmitGeneratedCodeAttribute(method); method.Name = functionImport.Name; method.Attributes = GetFunctionImportAccessibility(functionImport) | MemberAttributes.Final; UniqueIdentifierService uniqueIdentifierService = new UniqueIdentifierService( this.Generator.IsLanguageCaseSensitive, s => Utils.FixParameterName(s)); // determine element return type EdmType returnType = GetReturnTypeFromFunctionImport(functionImport); if (Helper.IsCollectionType(returnType)) { // get the type in the collection returnType = ((CollectionType)returnType).TypeUsage.EdmType; } CodeTypeReference elementType = Generator.GetLeastPossibleQualifiedTypeReference(returnType); method.ReturnType = TypeReference.ObjectResult(elementType); // generate <summary> comments based on CSDL Documentation element CommentEmitter.EmitSummaryComments(functionImport, method.Comments); // build up list of arguments to ExecuteFunction List <CodeExpression> executeArguments = new List <CodeExpression>(); executeArguments.Add(new CodePrimitiveExpression(functionImport.Name)); // first argument is the name of the function foreach (FunctionParameter parameter in functionImport.Parameters) { CreateFunctionArgument(method, uniqueIdentifierService, parameter); } // add fields representing object parameters foreach (FunctionParameter parameter in functionImport.Parameters) { if (parameter.Mode == ParameterMode.In) { CodeExpression variableReference = CreateFunctionParameter(method, uniqueIdentifierService, parameter); executeArguments.Add(variableReference); } else { // the parameter is already being passed in as an argument; just remember it and // pass it in as an argument string adjustedParameterName; if (!uniqueIdentifierService.TryGetAdjustedName(parameter, out adjustedParameterName)) { Debug.Fail("parameter must be registered in identifier service"); } executeArguments.Add(new CodeVariableReferenceExpression(adjustedParameterName)); } } // Add call to ExecuteFunction // return ExecuteFunction<elementType>("FunctionImportName", { object parameters }); CodeMethodReferenceExpression executeFunctionMethod = new CodeMethodReferenceExpression( new CodeBaseReferenceExpression(), "ExecuteFunction", new CodeTypeReference[] { elementType }); method.Statements.Add( new CodeMethodReturnStatement( new CodeMethodInvokeExpression(executeFunctionMethod, executeArguments.ToArray()) ) ); // invoke the ExecuteFunction method passing in parameters return(method); }
private CodeMemberProperty CreateEntitySetProperty(EntitySet set) { Debug.Assert(set != null, "Property is Null"); // trying to get // // [System.ComponentModel.Browsable(false)] // public ObjectQuery<Customer> Customers // { // get // { // if ((this._Customers == null)) // { // this._Customers = base.CreateQuery<Customer>("[Customers]"); // } // return this._Customers; // } // } // CodeMemberProperty codeProperty = new CodeMemberProperty(); Generator.AttributeEmitter.EmitGeneratedCodeAttribute(codeProperty); codeProperty.Attributes = MemberAttributes.Final | GetEntitySetPropertyAccessibility(set); codeProperty.Name = set.Name; codeProperty.HasGet = true; codeProperty.HasSet = false; // Determine type to use for field/property and name of factory method on ObjectContext string typeName = "ObjectQuery"; string createMethodName = "CreateQuery"; // When the EntitySet name is used as CommandText, it should be quoted string createMethodArgument = "[" + set.Name + "]"; CodeTypeReference genericParameter = Generator.GetLeastPossibleQualifiedTypeReference(set.ElementType); codeProperty.Type = TypeReference.AdoFrameworkGenericClass(typeName, 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 <CodeAttributeDeclaration> 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 <CodeStatement> 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(), createMethodName, new CodeTypeReference[] { genericParameter } ), new CodePrimitiveExpression(createMethodArgument) ) ) ) ); codeProperty.GetStatements.Add( new CodeMethodReturnStatement( new CodeFieldReferenceExpression( ThisRef, fieldName ) ) ); // property summary CommentEmitter.EmitSummaryComments(set, codeProperty.Comments); return(codeProperty); }
/// <summary> /// Creates the necessary constructors for the entity container. /// </summary> private void CreateConstructors(CodeTypeDeclaration typeDecl) { // Empty constructor. // // public ctor() // : base("name=" + ContainerName, "ContainerName") // { // this.OnContextCreated(); // } CodeConstructor emptyCtor = new CodeConstructor(); emptyCtor.Attributes = MemberAttributes.Public; emptyCtor.BaseConstructorArgs.Add(new CodePrimitiveExpression("name=" + Item.Name)); emptyCtor.BaseConstructorArgs.Add(new CodePrimitiveExpression(Item.Name)); CommentEmitter.EmitSummaryComments(Strings.EmptyCtorSummaryComment(Item.Name, Item.Name), emptyCtor.Comments); emptyCtor.Statements.Add(OnContextCreatedCodeMethodInvokeExpression()); typeDecl.Members.Add(emptyCtor); // Constructor that takes a connection string. // // public ctor(string connectionString) // : base(connectionString, "ContainerName") // { // this.OnContextCreated(); // } CodeConstructor connectionStringCtor = new CodeConstructor(); connectionStringCtor.Attributes = MemberAttributes.Public; CodeParameterDeclarationExpression connectionStringParam = new CodeParameterDeclarationExpression(TypeReference.String, "connectionString"); connectionStringCtor.Parameters.Add(connectionStringParam); connectionStringCtor.BaseConstructorArgs.Add(new CodeArgumentReferenceExpression(connectionStringParam.Name)); connectionStringCtor.BaseConstructorArgs.Add(new CodePrimitiveExpression(Item.Name)); CommentEmitter.EmitSummaryComments(Strings.CtorSummaryComment(Item.Name), connectionStringCtor.Comments); connectionStringCtor.Statements.Add(OnContextCreatedCodeMethodInvokeExpression()); typeDecl.Members.Add(connectionStringCtor); // Constructor that takes a connection // // public ctor(System.Data.EntityClient.EntityConnection connection) // : base(connection, "ContainerName") // { // this.OnContextCreated(); // } CodeConstructor connectionWorkspaceCtor = new CodeConstructor(); connectionWorkspaceCtor.Attributes = MemberAttributes.Public; CodeParameterDeclarationExpression connectionParam = new CodeParameterDeclarationExpression(TypeReference.AdoEntityClientType("EntityConnection"), "connection"); connectionWorkspaceCtor.Parameters.Add(connectionParam); connectionWorkspaceCtor.BaseConstructorArgs.Add(new CodeArgumentReferenceExpression(connectionParam.Name)); connectionWorkspaceCtor.BaseConstructorArgs.Add(new CodePrimitiveExpression(Item.Name)); CommentEmitter.EmitSummaryComments(Strings.CtorSummaryComment(Item.Name), connectionWorkspaceCtor.Comments); connectionWorkspaceCtor.Statements.Add(OnContextCreatedCodeMethodInvokeExpression()); typeDecl.Members.Add(connectionWorkspaceCtor); }
/// <summary> /// Emit static factory method which creates an instance of the class and initializes /// non-nullable properties (taken as arguments) /// </summary> /// <param name="typeDecl"></param> protected virtual void EmitFactoryMethod(CodeTypeDeclaration typeDecl) { // build list of non-nullable properties ReadOnlyMetadataCollection <EdmProperty> properties = GetProperties(); List <EdmProperty> parameters = new List <EdmProperty>(properties.Count); foreach (EdmProperty property in properties) { bool include = IncludeFieldInFactoryMethod(property); if (include) { parameters.Add(property); } } // if there are no parameters, we don't emit anything (1 is for the null element) // nor do we emit everything if this is the Ref propertied ctor and the parameter list is the same as the many parametered ctor if (parameters.Count < 1) { return; } CodeMemberMethod method = new CodeMemberMethod(); CodeTypeReference typeRef = TypeReference.FromString(Item.Name); UniqueIdentifierService uniqueIdentifierService = new UniqueIdentifierService(Generator.IsLanguageCaseSensitive); string instanceName = uniqueIdentifierService.AdjustIdentifier(Utils.CamelCase(Item.Name)); // public static Class CreateClass(...) method.Attributes = MemberAttributes.Static | MemberAttributes.Public; method.Name = "Create" + Item.Name; if (NavigationPropertyEmitter.IsNameAlreadyAMemberName(Item, method.Name, Generator.LanguageAppropriateStringComparer)) { Generator.AddError(Strings.GeneratedFactoryMethodNameConflict(method.Name, Item.Name), ModelBuilderErrorCode.GeneratedFactoryMethodNameConflict, EdmSchemaErrorSeverity.Error); } method.ReturnType = typeRef; AttributeEmitter.AddGeneratedCodeAttribute(method); // output method summary comments CommentEmitter.EmitSummaryComments(Strings.FactoryMethodSummaryComment(Item.Name), method.Comments); // Class class = new Class(); CodeVariableDeclarationStatement createNewInstance = new CodeVariableDeclarationStatement( typeRef, instanceName, new CodeObjectCreateExpression(typeRef)); method.Statements.Add(createNewInstance); CodeVariableReferenceExpression instanceRef = new CodeVariableReferenceExpression(instanceName); // iterate over the properties figuring out which need included in the factory method foreach (EdmProperty property in parameters) { // CreateClass( ... , propType propName ...) PropertyEmitter propertyEmitter = new PropertyEmitter(Generator, property, UsingStandardBaseClass); CodeTypeReference propertyTypeReference = propertyEmitter.PropertyType; String parameterName = uniqueIdentifierService.AdjustIdentifier(Utils.FixParameterName(propertyEmitter.PropertyName, "argument")); parameterName = Utils.SetSpecialCaseForFxCopOnPropertyName(parameterName); CodeParameterDeclarationExpression paramDecl = new CodeParameterDeclarationExpression( propertyTypeReference, parameterName); CodeArgumentReferenceExpression paramRef = new CodeArgumentReferenceExpression(paramDecl.Name); method.Parameters.Add(paramDecl); // add comment describing the parameter CommentEmitter.EmitParamComments(paramDecl, Strings.FactoryParamCommentGeneral(propertyEmitter.PropertyName), method.Comments); CodeExpression newPropertyValue; if (TypeSemantics.IsComplexType(propertyEmitter.Item.TypeUsage)) { List <CodeExpression> complexVerifyParameters = new List <CodeExpression>(); complexVerifyParameters.Add(paramRef); complexVerifyParameters.Add(new CodePrimitiveExpression(propertyEmitter.PropertyName)); // if (null == param) { throw new ArgumentNullException("PropertyName"); } method.Statements.Add( new CodeConditionStatement( EmitExpressionEqualsNull(paramRef), new CodeThrowExceptionStatement( new CodeObjectCreateExpression( TypeReference.ForType(typeof(ArgumentNullException)), new CodePrimitiveExpression(parameterName) ) ) ) ); newPropertyValue = paramRef; } else { newPropertyValue = paramRef; } // Scalar property: // Property = param; // Complex property: // Property = StructuralObject.VerifyComplexObjectIsNotNull(param, propertyName); method.Statements.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(instanceRef, propertyEmitter.PropertyName), newPropertyValue)); } // return class; method.Statements.Add(new CodeMethodReturnStatement(instanceRef)); // actually add the method to the class typeDecl.Members.Add(method); }
/// <summary> /// Generate a navigation property /// </summary> /// <param name="target">the other end</param> /// <param name="referenceProperty">True to emit Reference navigation property</param> /// <returns>the generated property</returns> private CodeMemberProperty EmitNavigationProperty(RelationshipEndMember target, bool referenceProperty) { CodeTypeReference typeRef = GetReturnType(target, referenceProperty); // raise the PropertyGenerated event PropertyGeneratedEventArgs eventArgs = new PropertyGeneratedEventArgs(Item, null, // no backing field typeRef); this.Generator.RaisePropertyGeneratedEvent(eventArgs); // [System.ComponentModel.Browsable(false)] // public TargetType TargetName // public EntityReference<TargetType> TargetName // or // public EntityCollection<targetType> TargetNames CodeMemberProperty property = new CodeMemberProperty(); if (referenceProperty) { AttributeEmitter.AddBrowsableAttribute(property); Generator.AttributeEmitter.EmitGeneratedCodeAttribute(property); } else { Generator.AttributeEmitter.EmitNavigationPropertyAttributes(Generator, target, property, eventArgs.AdditionalAttributes); // Only reference navigation properties are currently currently supported with XML serialization // and thus we should use the XmlIgnore and SoapIgnore attributes on other property types. AttributeEmitter.AddIgnoreAttributes(property); } AttributeEmitter.AddDataMemberAttribute(property); CommentEmitter.EmitSummaryComments(Item, property.Comments); property.Name = Item.Name; if (referenceProperty) { property.Name += "Reference"; if (IsNameAlreadyAMemberName(Item.DeclaringType, property.Name, Generator.LanguageAppropriateStringComparer)) { Generator.AddError(Strings.GeneratedNavigationPropertyNameConflict(Item.Name, Item.DeclaringType.Name, property.Name), ModelBuilderErrorCode.GeneratedNavigationPropertyNameConflict, EdmSchemaErrorSeverity.Error, Item.DeclaringType.FullName, property.Name); } } if (eventArgs.ReturnType != null && !eventArgs.ReturnType.Equals(typeRef)) { property.Type = eventArgs.ReturnType; } else { property.Type = typeRef; } property.Attributes = MemberAttributes.Final; CodeMethodInvokeExpression getMethod = EmitGetMethod(target); CodeExpression getReturnExpression; property.Attributes |= AccessibilityFromGettersAndSetters(Item); // setup the accessibility of the navigation property setter and getter MemberAttributes propertyAccessibility = property.Attributes & MemberAttributes.AccessMask; PropertyEmitter.AddGetterSetterFixUp(Generator.FixUps, GetFullyQualifiedPropertyName(property.Name), PropertyEmitter.GetGetterAccessibility(Item), propertyAccessibility, true); PropertyEmitter.AddGetterSetterFixUp(Generator.FixUps, GetFullyQualifiedPropertyName(property.Name), PropertyEmitter.GetSetterAccessibility(Item), propertyAccessibility, false); if (target.RelationshipMultiplicity != RelationshipMultiplicity.Many) { // insert user-supplied Set code here, before the assignment // List <CodeStatement> additionalSetStatements = eventArgs.AdditionalSetStatements; if (additionalSetStatements != null && additionalSetStatements.Count > 0) { try { property.SetStatements.AddRange(additionalSetStatements.ToArray()); } catch (ArgumentNullException ex) { Generator.AddError(Strings.InvalidSetStatementSuppliedForProperty(Item.Name), ModelBuilderErrorCode.InvalidSetStatementSuppliedForProperty, EdmSchemaErrorSeverity.Error, ex); } } CodeExpression valueRef = new CodePropertySetValueReferenceExpression(); if (typeRef != eventArgs.ReturnType) { // we need to cast to the actual type valueRef = new CodeCastExpression(typeRef, valueRef); } if (referenceProperty) { // get // return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<TTargetEntity>("CSpaceQualifiedRelationshipName", "TargetRoleName"); getReturnExpression = getMethod; // set // if (value != null) // { // ((IEntityWithRelationships)this).RelationshipManager.InitializeRelatedReference<TTargetEntity>"CSpaceQualifiedRelationshipName", "TargetRoleName", value); // } CodeMethodReferenceExpression initReferenceMethod = new CodeMethodReferenceExpression(); initReferenceMethod.MethodName = "InitializeRelatedReference"; initReferenceMethod.TypeArguments.Add(Generator.GetLeastPossibleQualifiedTypeReference(GetEntityType(target))); initReferenceMethod.TargetObject = new CodePropertyReferenceExpression( new CodeCastExpression(TypeReference.IEntityWithRelationshipsTypeBaseClass, ThisRef), "RelationshipManager"); // relationships aren't backed by types so we won't map the namespace // or we can't find the relationship again later string cspaceNamespaceNameQualifiedRelationshipName = target.DeclaringType.FullName; property.SetStatements.Add( new CodeConditionStatement( EmitExpressionDoesNotEqualNull(valueRef), new CodeExpressionStatement( new CodeMethodInvokeExpression( initReferenceMethod, new CodeExpression[] { new CodePrimitiveExpression(cspaceNamespaceNameQualifiedRelationshipName), new CodePrimitiveExpression(target.Name), valueRef })))); } else { CodePropertyReferenceExpression valueProperty = new CodePropertyReferenceExpression(getMethod, ValuePropertyName); // get // return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<TTargetEntity>("CSpaceQualifiedRelationshipName", "TargetRoleName").Value; getReturnExpression = valueProperty; // set // ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<TTargetEntity>("CSpaceQualifiedRelationshipName", "TargetRoleName").Value = value; property.SetStatements.Add( new CodeAssignStatement(valueProperty, valueRef)); } } else { // get // return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedCollection<TTargetEntity>("CSpaceQualifiedRelationshipName", "TargetRoleName"); getReturnExpression = getMethod; // set // if (value != null) // { // ((IEntityWithRelationships)this).RelationshipManager.InitializeRelatedCollection<TTargetEntity>"CSpaceQualifiedRelationshipName", "TargetRoleName", value); // } CodeExpression valueRef = new CodePropertySetValueReferenceExpression(); CodeMethodReferenceExpression initCollectionMethod = new CodeMethodReferenceExpression(); initCollectionMethod.MethodName = "InitializeRelatedCollection"; initCollectionMethod.TypeArguments.Add(Generator.GetLeastPossibleQualifiedTypeReference(GetEntityType(target))); initCollectionMethod.TargetObject = new CodePropertyReferenceExpression( new CodeCastExpression(TypeReference.IEntityWithRelationshipsTypeBaseClass, ThisRef), "RelationshipManager"); // relationships aren't backed by types so we won't map the namespace // or we can't find the relationship again later string cspaceNamespaceNameQualifiedRelationshipName = target.DeclaringType.FullName; property.SetStatements.Add( new CodeConditionStatement( EmitExpressionDoesNotEqualNull(valueRef), new CodeExpressionStatement( new CodeMethodInvokeExpression( initCollectionMethod, new CodeExpression[] { new CodePrimitiveExpression(cspaceNamespaceNameQualifiedRelationshipName), new CodePrimitiveExpression(target.Name), valueRef })))); } // if additional Get statements were specified by the event subscriber, insert them now // List <CodeStatement> additionalGetStatements = eventArgs.AdditionalGetStatements; if (additionalGetStatements != null && additionalGetStatements.Count > 0) { try { property.GetStatements.AddRange(additionalGetStatements.ToArray()); } catch (ArgumentNullException ex) { Generator.AddError(Strings.InvalidGetStatementSuppliedForProperty(Item.Name), ModelBuilderErrorCode.InvalidGetStatementSuppliedForProperty, EdmSchemaErrorSeverity.Error, ex); } } property.GetStatements.Add(new CodeMethodReturnStatement(getReturnExpression)); return(property); }
/// <summary> /// Generate a navigation property /// </summary> /// <param name="target">the other end</param> /// <param name="referenceProperty">True to emit Reference navigation property</param> /// <returns>the generated property</returns> private CodeMemberProperty EmitNavigationProperty(RelationshipEndMember target) { CodeTypeReference typeRef = GetReturnType(target); // raise the PropertyGenerated event PropertyGeneratedEventArgs eventArgs = new PropertyGeneratedEventArgs(Item, null, // no backing field typeRef); this.Generator.RaisePropertyGeneratedEvent(eventArgs); // [System.ComponentModel.Browsable(false)] // public TargetType TargetName // public EntityReference<TargetType> TargetName // or // public EntityCollection<targetType> TargetNames CodeMemberProperty property = new CodeMemberProperty(); // Only reference navigation properties are currently currently supported with XML serialization // and thus we should use the XmlIgnore and SoapIgnore attributes on other property types. AttributeEmitter.AddIgnoreAttributes(property); AttributeEmitter.AddBrowsableAttribute(property); AttributeEmitter.AddGeneratedCodeAttribute(property); CommentEmitter.EmitSummaryComments(Item, property.Comments); property.Name = Item.Name; if (eventArgs.ReturnType != null && !eventArgs.ReturnType.Equals(typeRef)) { property.Type = eventArgs.ReturnType; } else { property.Type = typeRef; } property.Attributes = MemberAttributes.Final; CodeExpression getMethod = EmitGetMethod(target); CodeExpression getReturnExpression; if (target.RelationshipMultiplicity != RelationshipMultiplicity.Many) { property.Attributes |= AccessibilityFromGettersAndSetters(Item); // insert user-supplied Set code here, before the assignment // List <CodeStatement> additionalSetStatements = eventArgs.AdditionalSetStatements; if (additionalSetStatements != null && additionalSetStatements.Count > 0) { try { property.SetStatements.AddRange(additionalSetStatements.ToArray()); } catch (ArgumentNullException e) { Generator.AddError(Strings.InvalidSetStatementSuppliedForProperty(Item.Name), ModelBuilderErrorCode.InvalidSetStatementSuppliedForProperty, EdmSchemaErrorSeverity.Error, e); } } CodeExpression valueRef = new CodePropertySetValueReferenceExpression(); if (typeRef != eventArgs.ReturnType) { // we need to cast to the actual type valueRef = new CodeCastExpression(typeRef, valueRef); } CodeExpression valueProperty = getMethod; // get // return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<TTargetEntity>("CSpaceQualifiedRelationshipName", "TargetRoleName").Value; getReturnExpression = valueProperty; // set // ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<TTargetEntity>("CSpaceQualifiedRelationshipName", "TargetRoleName").Value = value; property.SetStatements.Add( new CodeAssignStatement(valueProperty, valueRef)); // setup the accessibility of the navigation property setter and getter MemberAttributes propertyAccessibility = property.Attributes & MemberAttributes.AccessMask; PropertyEmitter.AddGetterSetterFixUp(Generator.FixUps, GetFullyQualifiedPropertyName(property.Name), PropertyEmitter.GetGetterAccessibility(Item), propertyAccessibility, true); PropertyEmitter.AddGetterSetterFixUp(Generator.FixUps, GetFullyQualifiedPropertyName(property.Name), PropertyEmitter.GetSetterAccessibility(Item), propertyAccessibility, false); List <CodeStatement> additionalAfterSetStatements = eventArgs.AdditionalAfterSetStatements; if (additionalAfterSetStatements != null && additionalAfterSetStatements.Count > 0) { try { property.SetStatements.AddRange(additionalAfterSetStatements.ToArray()); } catch (ArgumentNullException e) { Generator.AddError(Strings.InvalidSetStatementSuppliedForProperty(Item.Name), ModelBuilderErrorCode.InvalidSetStatementSuppliedForProperty, EdmSchemaErrorSeverity.Error, e); } } } else { property.Attributes |= PropertyEmitter.GetGetterAccessibility(Item); // get // return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedCollection<TTargetEntity>("CSpaceQualifiedRelationshipName", "TargetRoleName"); getReturnExpression = getMethod; // set // if (value != null) ==> Only for non-binding scenario // { // this = // this.OnPropertyChanged("") // } CodeExpression valueRef = new CodePropertySetValueReferenceExpression(); CodeStatementCollection csc = null; if (this.Generator.UseDataServiceCollection == true) { csc = property.SetStatements; } else { CodeConditionStatement ccs = new CodeConditionStatement(EmitExpressionDoesNotEqualNull(valueRef)); property.SetStatements.Add(ccs); csc = ccs.TrueStatements; } csc.Add(new CodeAssignStatement(getMethod, valueRef)); if (eventArgs.AdditionalAfterSetStatements != null) { try { foreach (CodeStatement s in eventArgs.AdditionalAfterSetStatements) { csc.Add(s); } } catch (ArgumentNullException e) { Generator.AddError(Strings.InvalidSetStatementSuppliedForProperty(Item.Name), ModelBuilderErrorCode.InvalidSetStatementSuppliedForProperty, EdmSchemaErrorSeverity.Error, e); } } } // if additional Get statements were specified by the event subscriber, insert them now // List <CodeStatement> additionalGetStatements = eventArgs.AdditionalGetStatements; if (additionalGetStatements != null && additionalGetStatements.Count > 0) { try { property.GetStatements.AddRange(additionalGetStatements.ToArray()); } catch (ArgumentNullException ex) { Generator.AddError(Strings.InvalidGetStatementSuppliedForProperty(Item.Name), ModelBuilderErrorCode.InvalidGetStatementSuppliedForProperty, EdmSchemaErrorSeverity.Error, ex); } } property.GetStatements.Add(new CodeMethodReturnStatement(getReturnExpression)); return(property); }
/// <summary> /// Creates the CodeTypeDeclarations necessary to generate the code for the EntityContainer schema element /// </summary> /// <returns></returns> 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 <StructuralType>() 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 = CreateEntitySetAddObjectMethod(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); }
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)); AttributeEmitter.AddGeneratedCodeAttribute(resolveTypeFromName); 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)), false) // DEVNOTE(Microsoft): we should use GetType(xxx, FALSE) here so it will not throw and fall back to null // GetType(type, bool throw, bool ignoreCase) does not exist in SL, do not use! 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(false) ) ) ) ); } 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)); AttributeEmitter.AddGeneratedCodeAttribute(resolveNameFromType); 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); }