internal CodeGen(ICodeGenContext context) { this.context = context; this.cg = context as ConstructorGen; if (cg != null && cg.IsStatic) // #14 - cg is relevant for instance constructors - it wreaks havoc in a static constructor cg = null; il = context.GetILGenerator(); }
/// <summary> /// Generates the business logic class type. We override this to control the base class and imports /// </summary> /// <param name="codeGenContext">The context to use to generate code.</param> /// <param name="codeNamespace">The namespace into which to generate code.</param> /// <param name="className">The name to use for the class.</param> /// <returns>The new type</returns> protected override CodeTypeDeclaration CreateBusinessLogicClass(ICodeGenContext codeGenContext, CodeNamespace codeNamespace, string className) { // Add an import for our domain service foreach (string import in BusinessLogicClassConstants.LinqToEntitiesImports) { codeNamespace.Imports.Add(new CodeNamespaceImport(import)); } // Add an import for the namespace of the DomainContext if (this.ContextType.Namespace != codeNamespace.Name) { codeNamespace.Imports.Add(new CodeNamespaceImport(this.ContextType.Namespace)); } // Add to the set of known references codeGenContext.AddReference(typeof(ObjectContext).Assembly.FullName); codeGenContext.AddReference(typeof(LinqToEntitiesDomainService<>).Assembly.FullName); CodeTypeDeclaration businessLogicClass = CodeGenUtilities.CreateTypeDeclaration(className, codeNamespace.Name); CodeTypeReference baseClass = new CodeTypeReference(BusinessLogicClassConstants.LinqToEntitiesDomainServiceTypeName, new CodeTypeReference(this.ContextType.Name)); businessLogicClass.BaseTypes.Add(baseClass); return businessLogicClass; }
/// <summary> /// Generates the update domain operation entry /// </summary> /// <param name="codeGenContext">The code gen context.></param> /// <param name="businessLogicClass">The business logic class.</param> /// <param name="entity">The entity.</param> protected override void GenerateUpdateMethod(ICodeGenContext codeGenContext, CodeTypeDeclaration businessLogicClass, IBusinessLogicEntity entity) { string currentParameterName = "current" + entity.ClrType.Name; // public void Update$EntityName$($entityType$ current) CodeMemberMethod method = new CodeMemberMethod(); businessLogicClass.Members.Add(method); LinqToSqlEntity ltsEntity = (LinqToSqlEntity)entity; method.Name = "Update" + CodeGenUtilities.MakeLegalEntityName(entity.Name); method.Attributes = MemberAttributes.Public | MemberAttributes.Final; // final needed to prevent virtual // parameter declaration method.Parameters.Add(new CodeParameterDeclarationExpression(entity.ClrType.Name, currentParameterName)); if (!ltsEntity.HasTimestampMember) { // this.ChangeSet.GetOriginal(current) CodeExpression changeSetRef = new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "ChangeSet"); CodeMethodReferenceExpression getOrigMethodRef = new CodeMethodReferenceExpression(changeSetRef, "GetOriginal"); CodeMethodInvokeExpression changeSetGetOrig = new CodeMethodInvokeExpression(getOrigMethodRef, new CodeArgumentReferenceExpression(currentParameterName)); // this.DataContext.$TablePropertyName$.Attach(current, this.ChangeSet.GetOriginal(current)) CodeExpression contextRef = new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "DataContext"); CodeExpression tableRef = new CodePropertyReferenceExpression(contextRef, ltsEntity.TablePropertyName); CodeMethodInvokeExpression attachCall = new CodeMethodInvokeExpression(tableRef, "Attach", new CodeArgumentReferenceExpression(currentParameterName), changeSetGetOrig); method.Statements.Add(attachCall); } else { // this.DataContext.$TablePropertyName$.Attach(current, true) CodeExpression contextRef = new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "DataContext"); CodeExpression tableRef = new CodePropertyReferenceExpression(contextRef, ltsEntity.TablePropertyName); CodeMethodInvokeExpression attachCall = new CodeMethodInvokeExpression(tableRef, "Attach", new CodeArgumentReferenceExpression(currentParameterName), new CodePrimitiveExpression(true)); method.Statements.Add(attachCall); } }
/// <summary> /// Creates the business logic class. Overridden to add imports, base class, etc. /// </summary> /// <param name="codeGenContext">The code gen context.></param> /// <param name="codeNamespace">The namespace name.</param> /// <param name="className">The class name.</param> /// <returns>the new type</returns> protected override CodeTypeDeclaration CreateBusinessLogicClass(ICodeGenContext codeGenContext, CodeNamespace codeNamespace, string className) { Debug.Assert(LinqToSqlContext.linqToSqlDomainServiceAssemblyPath != null, "Unexpected method call when LinqToSqlDomainService assembly path has not been initialized!"); if (LinqToSqlContext.linqToSqlDomainServiceAssemblyPath == null) { return null; } // Add an import for our domain service foreach (string import in BusinessLogicClassConstants.LinqToSqlImports) { codeNamespace.Imports.Add(new CodeNamespaceImport(import)); } // Add an import for the namespace of the DomainContext if (this.ContextType.Namespace != codeNamespace.Name) { codeNamespace.Imports.Add(new CodeNamespaceImport(this.ContextType.Namespace)); } // Add to the set of known references codeGenContext.AddReference(typeof(DataContext).Assembly.FullName); codeGenContext.AddReference(LinqToSqlContext.linqToSqlDomainServiceAssemblyPath); CodeTypeDeclaration businessLogicClass = CodeGenUtilities.CreateTypeDeclaration(className, codeNamespace.Name); CodeTypeReference baseClass = new CodeTypeReference(BusinessLogicClassConstants.LinqToSqlDomainServiceTypeName, new CodeTypeReference(this.ContextType.Name)); businessLogicClass.BaseTypes.Add(baseClass); return businessLogicClass; }
/// <summary> /// Creates the "insert" method for the entity /// </summary> /// <param name="codeGenContext">The context into which to generate code. It cannot be null.</param> /// <param name="businessLogicClass">The class into which to generate the method</param> /// <param name="entity">The entity which will be affected by this method</param> protected virtual void GenerateInsertMethod(ICodeGenContext codeGenContext, CodeTypeDeclaration businessLogicClass, IBusinessLogicEntity entity) { }
internal void RegisterForCompletion(ICodeGenContext routine) { definitionQueue.Add(routine); completionQueue.Add(routine); }
/// <summary> /// Tests whether the specified helper member has been generated, and if not, invokes /// a callback to generate it. /// </summary> /// <param name="codeGenContext">The context in which we are generating code.</param> /// <param name="businessLogicClass">The class containing the generated code.</param> /// <param name="helperMemberName">The name of the helper member.</param> /// <param name="generatorCallback">Callback that will create this helper if it does not yet exist.</param> public static void GenerateHelperMemberIfNecessary(ICodeGenContext codeGenContext, CodeTypeDeclaration businessLogicClass, string helperMemberName, Func<CodeTypeMember> generatorCallback) { System.Diagnostics.Debug.Assert(codeGenContext != null, "CodeGenContext cannot be null"); System.Diagnostics.Debug.Assert(businessLogicClass != null, "BusinessLogicClass cannot be null"); System.Diagnostics.Debug.Assert(!string.IsNullOrEmpty(helperMemberName), "Helper member name cannot be empty."); System.Diagnostics.Debug.Assert(generatorCallback != null, "callback cannot be null"); Dictionary<string, CodeTypeMember> memberDictionary = BusinessLogicContext.GetHelperMemberDictionary(businessLogicClass); if (!memberDictionary.ContainsKey(helperMemberName)) { CodeTypeMember member = generatorCallback(); if (member != null) { memberDictionary[helperMemberName] = member; } } }
/// <summary> /// Generates additional metadata classes for the given entity if necessary. /// </summary> /// <param name="codeGenContext">The context to use to generate code.</param> /// <param name="optionalSuffix">If not null, optional suffix to class name and namespace</param> /// <param name="entity">The entity for which to generate the additional metadata.</param> /// <returns><c>true</c> means at least some code was generated.</returns> /// <remarks> /// This default implementation of the virtual method does not generate any additional classes. It needs to be overridden in the derived /// classes to generate additional metadata classes if necessary. /// </remarks> protected virtual bool GenerateAdditionalMetadataClasses(ICodeGenContext codeGenContext, string optionalSuffix, BusinessLogicEntity entity) { return false; }
/// <summary> /// Creates the entire business logic class in the specified namespace /// </summary> /// <param name="codeGenContext">The context into which to generate code. It cannot be null.</param> /// <param name="codeNamespace">The namespace object into which the type should be defined.</param> /// <param name="className">The name of the class. It cannot be null.</param> /// <returns>A new CodeTypeDeclaration for the generated class.</returns> protected virtual CodeTypeDeclaration CreateBusinessLogicClass(ICodeGenContext codeGenContext, CodeNamespace codeNamespace, string className) { CodeTypeDeclaration businessLogicClass = CodeGenUtilities.CreateTypeDeclaration(className, codeNamespace.Name); businessLogicClass.BaseTypes.Add(BusinessLogicClassConstants.DomainServiceTypeName); return businessLogicClass; }
/// <summary> /// Generates the select domain operation entry /// </summary> /// <param name="codeGenContext">The code generation context.</param> /// <param name="businessLogicClass">Contains the business logic.</param> /// <param name="entity">The entity.</param> /// <returns>The newly created method.</returns> protected override CodeMemberMethod GenerateSelectMethod(ICodeGenContext codeGenContext, CodeTypeDeclaration businessLogicClass, IBusinessLogicEntity entity) { CodeMemberMethod method = null; LinqToEntitiesEntity efDbEntity = entity as LinqToEntitiesEntity; if (efDbEntity != null && efDbEntity.DefaultObjectSetName != null) { // public IQueryable<$entityType$> GetEntities() method = new CodeMemberMethod(); businessLogicClass.Members.Add(method); // Add developer comment explaining they can add additional parameters method.Comments.Add(new CodeCommentStatement(Resources.BusinessLogicClass_Query_Method_Remarks, false)); // And for EF, we add an additional comment warning they need to add ordering if they want paging string queryComment = String.Format(CultureInfo.CurrentCulture, Resources.BusinessLogicClass_Query_Method_EF_Remarks, efDbEntity.DefaultObjectSetName); method.Comments.Add(new CodeCommentStatement(queryComment, false)); method.Name = "Get" + CodeGenUtilities.MakeLegalEntityName(efDbEntity.DefaultObjectSetName); method.ReturnType = new CodeTypeReference("IQueryable", new CodeTypeReference(entity.Name)); method.Attributes = MemberAttributes.Public | MemberAttributes.Final; // final needed to prevent virtual // return this.DbContext.$TablePropertyName$ CodeExpression contextExpr = LinqToEntitiesDbContext.GetContextReferenceExpression(); CodeExpression expr = new CodePropertyReferenceExpression(contextExpr, efDbEntity.DefaultObjectSetName); CodeMethodReturnStatement returnStmt = new CodeMethodReturnStatement(expr); method.Statements.Add(returnStmt); } return method; }
/// <summary> /// Generates the business logic class type. We override this to control the base class and imports /// </summary> /// <param name="codeGenContext">The context to use to generate code.</param> /// <param name="codeNamespace">The namespace into which to generate code.</param> /// <param name="className">The name to use for the class.</param> /// <returns>The new type</returns> protected override CodeTypeDeclaration CreateBusinessLogicClass(ICodeGenContext codeGenContext, CodeNamespace codeNamespace, string className) { // Add an import for our domain service foreach (string import in BusinessLogicClassConstants.LinqToEntitiesDbImports) { codeNamespace.Imports.Add(new CodeNamespaceImport(import)); } // Add an import for the namespace of the DomainContext if (this.ContextType.Namespace != codeNamespace.Name) { codeNamespace.Imports.Add(new CodeNamespaceImport(BusinessLogicClassConstants.DbContextNamespace)); codeNamespace.Imports.Add(new CodeNamespaceImport(this.ContextType.Namespace)); } // Add to the set of known references codeGenContext.AddReference(typeof(EntityState).Assembly.FullName); // We used to add OpenRiaServices.DomainServices.EntityFramework, but due to // vstfdevdiv/DevDiv2 Bug 442272 - Domain Service Wizard failing when an EF DbContext is selected, // we need to avoid doing that. if (DbContextUtilities.DbContextTypeReference != null) { codeGenContext.AddReference(DbContextUtilities.DbContextTypeReference.Assembly.FullName); } CodeTypeDeclaration businessLogicClass = CodeGenUtilities.CreateTypeDeclaration(className, codeNamespace.Name); CodeTypeReference baseClass = new CodeTypeReference(BusinessLogicClassConstants.DbDomainServiceTypeName, new CodeTypeReference(this.ContextType.Name)); businessLogicClass.BaseTypes.Add(baseClass); return businessLogicClass; }
/// <summary> /// Tests whether we need to generate the GetEntityState helper method. We do for POCO types. /// If we determine we need to generate that helper, this method generates it and adds it to /// the list of helper methods that will be appended to the generated code. /// </summary> /// <param name="codeGenContext">The context in which we are generating code.</param> /// <param name="businessLogicClass">The class containing the generated code.</param> /// <param name="entity">The entity that we need to test to determine whether the helper is needed.</param> /// <returns><c>true</c> means the helper should be used.</returns> private static bool GenerateGetEntityStateIfNecessary(ICodeGenContext codeGenContext, CodeTypeDeclaration businessLogicClass, IBusinessLogicEntity entity) { if (typeof(EntityObject).IsAssignableFrom(entity.ClrType)) { return false; } BusinessLogicContext.GenerateHelperMemberIfNecessary(codeGenContext, businessLogicClass, LinqToEntitiesContext.GetEntityStateHelperMethodName, () => { return LinqToEntitiesContext.GenerateGetEntityState(codeGenContext, businessLogicClass); }); return true; }
/// <summary> /// Generates the GetEntityState helper method that allows POCO types to retrieve their /// entity state from the contect. It is not available on the POCO types directly. /// </summary> /// <param name="codeGenContext">The context in which we are generating code.</param> /// <param name="businessLogicClass">The class we are generating.</param> /// <returns>The <see cref="CodeTypeMember"/> containing the helper method.</returns> private static CodeTypeMember GenerateGetEntityState(ICodeGenContext codeGenContext, CodeTypeDeclaration businessLogicClass) { // Add an import for System.Data.Objects CodeNamespace codeNamespace = codeGenContext.GetNamespace(businessLogicClass); if (codeNamespace != null) { codeNamespace.Imports.Add(new CodeNamespaceImport("System.Data.Objects")); } //private EntityState GetEntityState(object entity) //{ // ObjectStateEntry stateEntry = null; // if (!this.ObjectContext.ObjectStateManager.TryGetObjectStateEntry(entity, out stateEntry)) // { // return EntityState.Detached; // } // return stateEntry.State; //} // Declaration CodeMemberMethod method = new CodeMemberMethod(); method.Name = LinqToEntitiesContext.GetEntityStateHelperMethodName; method.ReturnType = new CodeTypeReference(typeof(EntityState).Name); method.Attributes = MemberAttributes.Private; method.Parameters.Add(new CodeParameterDeclarationExpression(typeof(object), "entity")); // ObjectStateEntry stateEntry = null; method.Statements.Add(new CodeVariableDeclarationStatement("ObjectStateEntry", "stateEntry", new CodePrimitiveExpression(null))); CodeArgumentReferenceExpression entityArgRef = new CodeArgumentReferenceExpression("entity"); CodeExpression contextRef = new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "ObjectContext"); CodeFieldReferenceExpression detachedStateRef = new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(typeof(EntityState).Name), Enum.GetName(typeof(EntityState), EntityState.Detached)); CodePropertyReferenceExpression objectStateMgrRef = new CodePropertyReferenceExpression(contextRef, "ObjectStateManager"); CodeVariableReferenceExpression entityStateRef = new CodeVariableReferenceExpression("stateEntry"); // The "_out_" prefix will be replaced below with the language-appropriate modifier to make an out param. // CodeDom does not support this, so we must do some string manipulation CodeVariableReferenceExpression outEntityStateRef = new CodeVariableReferenceExpression("_out_stateEntry"); // this.ObjectContext.ObjectStateManager.TryGetObjectStateEntry(entity, out stateEntry) CodeMethodInvokeExpression getObjectStateEntryCall = new CodeMethodInvokeExpression(objectStateMgrRef, "TryGetObjectStateEntry", entityArgRef, outEntityStateRef); // if (...TryGet()) CodeExpression tryGetTest = CodeGenUtilities.MakeEqual(typeof(bool), getObjectStateEntryCall, new CodePrimitiveExpression(false), codeGenContext.IsCSharp); // if (...TryGet..) { return EntityState.Detached; } CodeMethodReturnStatement returnDetached = new CodeMethodReturnStatement(detachedStateRef); CodeConditionStatement ifTryGet = new CodeConditionStatement(tryGetTest, returnDetached); method.Statements.Add(ifTryGet); // Return entityState.State; method.Statements.Add(new CodeMethodReturnStatement(new CodePropertyReferenceExpression(entityStateRef, "State"))); // CodeDom does not support specifying 'out' parameters at the method call site. // So convert the entire method into a snippet of text StringBuilder snippet = null; CodeDomProvider provider = codeGenContext.Provider; using (StringWriter snippetWriter = new StringWriter(System.Globalization.CultureInfo.CurrentCulture)) { provider.GenerateCodeFromMember(method, snippetWriter, codeGenContext.CodeGeneratorOptions); snippet = snippetWriter.GetStringBuilder(); } // Our convention above is that "_out_" will be replaced by the language-appropriate "out" parameter modifier. // In the case of VB, it is the default snippet.Replace("_out_", codeGenContext.IsCSharp ? "out " : string.Empty); // We need to indent the entire snippet 2 levels string indent = codeGenContext.CodeGeneratorOptions.IndentString; indent += indent; string snippetText = indent + snippet.ToString().Replace(Environment.NewLine, Environment.NewLine + indent).TrimEnd(' '); CodeSnippetTypeMember methodAsText = new CodeSnippetTypeMember(snippetText); return methodAsText; }
/// <summary> /// Generates the delete domain operation entry /// </summary> /// <param name="codeGenContext">The context to use</param> /// <param name="businessLogicClass">The business logic class into which to generate it</param> /// <param name="entity">The entity for which to generate the method</param> protected override void GenerateDeleteMethod(ICodeGenContext codeGenContext, CodeTypeDeclaration businessLogicClass, IBusinessLogicEntity entity) { string parameterName = CodeGenUtilities.MakeLegalParameterName(entity.Name); // public void Delete$EntityName$($entityType$ $entityName$) CodeMemberMethod method = new CodeMemberMethod(); businessLogicClass.Members.Add(method); //LinqToEntitiesEntity efEntity = (LinqToEntitiesEntity)entity; method.Name = "Delete" + CodeGenUtilities.MakeLegalEntityName(entity.Name); method.Attributes = MemberAttributes.Public | MemberAttributes.Final; // final needed to prevent virtual // parameter declaration method.Parameters.Add(new CodeParameterDeclarationExpression(entity.ClrType.Name, parameterName)); // if ($entity$.EntityState != EntityState.Detached) // { // ObjectContext.ObjectStateManager.ChangeObjectState($entity$, EntityState.Deleted); // } // else // { // ObjectContext.Products.Attach($entity$); // ObjectContext.Products.DeleteObject($entity$); // } // // In the case of POCO objects, we use "this.GetEntityState(entity)" // rather than referring to the entity's EntityState property LinqToEntitiesEntity efEntity = (LinqToEntitiesEntity)entity; CodeArgumentReferenceExpression entityExpr = new CodeArgumentReferenceExpression(parameterName); // If this is a POCO class, we need to generate a call to a helper method to get // the EntityState, otherwise we can directly de-reference it on the entity // If this entity does not have an EntityState member, we need to use a helper method instead. // This call tells us whether we need this helper and, if so, generates it. bool useGetEntityStateHelper = LinqToEntitiesContext.GenerateGetEntityStateIfNecessary(codeGenContext, businessLogicClass, entity); CodeExpression getEntityStateExpr; if (useGetEntityStateHelper) { // this.GetEntityState($entity$)... getEntityStateExpr = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), LinqToEntitiesContext.GetEntityStateHelperMethodName, entityExpr); } else { // $entity$.EntityState... getEntityStateExpr = new CodePropertyReferenceExpression(entityExpr, LinqToEntitiesContext.EntityStatePropertyName); } CodeExpression contextRef = new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "ObjectContext"); CodePropertyReferenceExpression objectSetRef = new CodePropertyReferenceExpression(contextRef, efEntity.DefaultObjectSetName); CodeFieldReferenceExpression detachedStateRef = new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(typeof(EntityState).Name), Enum.GetName(typeof(EntityState), EntityState.Detached)); CodeExpression equalTest = CodeGenUtilities.MakeNotEqual(typeof(EntityState), getEntityStateExpr, detachedStateRef, codeGenContext.IsCSharp); CodeFieldReferenceExpression deletedStateRef = new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(typeof(EntityState).Name), Enum.GetName(typeof(EntityState), EntityState.Deleted)); CodePropertyReferenceExpression objectStateMgrRef = new CodePropertyReferenceExpression(contextRef, "ObjectStateManager"); CodeMethodInvokeExpression changeStateExpr = new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(objectStateMgrRef, "ChangeObjectState"), entityExpr, deletedStateRef); CodeStatement[] trueStatements = new CodeStatement[] { new CodeExpressionStatement(changeStateExpr) }; CodeMethodInvokeExpression attachCall = new CodeMethodInvokeExpression(objectSetRef, "Attach", entityExpr); CodeMethodInvokeExpression deleteCall = new CodeMethodInvokeExpression(objectSetRef, "DeleteObject", entityExpr); CodeStatement[] falseStatements = new CodeStatement[] { new CodeExpressionStatement(attachCall), new CodeExpressionStatement(deleteCall) }; CodeConditionStatement ifStmt = new CodeConditionStatement(equalTest, trueStatements, falseStatements); method.Statements.Add(ifStmt); }
/// <summary> /// Gets a <see cref="CodeTypeReference"/> for a CLR type. /// </summary> /// <param name="type">A CLR type.</param> /// <param name="codegenContext">A <see cref="ClientProxyGenerator"/>.</param> /// <param name="referencingType">The referencing type.</param> /// <returns>A <see cref="CodeTypeReference"/> for a CLR type.</returns> public static CodeTypeReference GetTypeReference(Type type, ICodeGenContext codegenContext, CodeTypeDeclaration referencingType) { if (type.IsPrimitive || type == typeof(void) || type == typeof(decimal) || type == typeof(string) || type == typeof(object)) { return new CodeTypeReference(type); } if (codegenContext != null && referencingType != null) { CodeNamespace ns = codegenContext.GetNamespace(referencingType); if (ns != null && !ns.Name.Equals(type.Namespace)) { // If the namespace is already imported, the following line will be a no-op. ns.Imports.Add(new CodeNamespaceImport(type.Namespace)); } } if (type.IsArray) { return new CodeTypeReference( CodeGenUtilities.GetTypeReference(type.GetElementType(), codegenContext, referencingType), type.GetArrayRank()); } if (type.IsGenericType) { Type[] genericArguments = type.GetGenericArguments(); CodeTypeReference[] typeArguments = new CodeTypeReference[genericArguments.Length]; for (int i = 0; i < genericArguments.Length; i++) { typeArguments[i] = GetTypeReference(genericArguments[i]); } return new CodeTypeReference(type.Name, typeArguments); } return new CodeTypeReference(type.Name); }
/// <summary> /// Generates the GetEntityState helper method that allows POCO types to retrieve their /// entity state from the contect. It is not available on the POCO types directly. /// </summary> /// <param name="codeGenContext">The context in which we are generating code.</param> /// <param name="businessLogicClass">The class we are generating.</param> /// <returns>The <see cref="CodeTypeMember"/> containing the helper method.</returns> private static CodeTypeMember GenerateGetEntityState(ICodeGenContext codeGenContext, CodeTypeDeclaration businessLogicClass) { // Add an import for System.Data.Objects CodeNamespace codeNamespace = codeGenContext.GetNamespace(businessLogicClass); if (codeNamespace != null) { codeNamespace.Imports.Add(new CodeNamespaceImport("System.Data.Objects")); } //private EntityState GetEntityState(object entity) //{ // ObjectStateEntry stateEntry = null; // if (!this.ObjectContext.ObjectStateManager.TryGetObjectStateEntry(entity, out stateEntry)) // { // return EntityState.Detached; // } // return stateEntry.State; //} // Declaration CodeMemberMethod method = new CodeMemberMethod(); method.Name = LinqToEntitiesContext.GetEntityStateHelperMethodName; method.ReturnType = new CodeTypeReference(typeof(EntityState).Name); method.Attributes = MemberAttributes.Private; method.Parameters.Add(new CodeParameterDeclarationExpression(typeof(object), "entity")); // ObjectStateEntry stateEntry = null; method.Statements.Add(new CodeVariableDeclarationStatement("ObjectStateEntry", "stateEntry", new CodePrimitiveExpression(null))); CodeArgumentReferenceExpression entityArgRef = new CodeArgumentReferenceExpression("entity"); CodeExpression contextRef = new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "ObjectContext"); CodeFieldReferenceExpression detachedStateRef = new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(typeof(EntityState).Name), Enum.GetName(typeof(EntityState), EntityState.Detached)); CodePropertyReferenceExpression objectStateMgrRef = new CodePropertyReferenceExpression(contextRef, "ObjectStateManager"); CodeVariableReferenceExpression entityStateRef = new CodeVariableReferenceExpression("stateEntry"); // The "_out_" prefix will be replaced below with the language-appropriate modifier to make an out param. // CodeDom does not support this, so we must do some string manipulation CodeVariableReferenceExpression outEntityStateRef = new CodeVariableReferenceExpression("_out_stateEntry"); // this.ObjectContext.ObjectStateManager.TryGetObjectStateEntry(entity, out stateEntry) CodeMethodInvokeExpression getObjectStateEntryCall = new CodeMethodInvokeExpression(objectStateMgrRef, "TryGetObjectStateEntry", entityArgRef, outEntityStateRef); // if (...TryGet()) CodeExpression tryGetTest = CodeGenUtilities.MakeEqual(typeof(bool), getObjectStateEntryCall, new CodePrimitiveExpression(false), codeGenContext.IsCSharp); // if (...TryGet..) { return EntityState.Detached; } CodeMethodReturnStatement returnDetached = new CodeMethodReturnStatement(detachedStateRef); CodeConditionStatement ifTryGet = new CodeConditionStatement(tryGetTest, returnDetached); method.Statements.Add(ifTryGet); // Return entityState.State; method.Statements.Add(new CodeMethodReturnStatement(new CodePropertyReferenceExpression(entityStateRef, "State"))); // CodeDom does not support specifying 'out' parameters at the method call site. // So convert the entire method into a snippet of text StringBuilder snippet = null; CodeDomProvider provider = codeGenContext.Provider; using (StringWriter snippetWriter = new StringWriter(System.Globalization.CultureInfo.CurrentCulture)) { provider.GenerateCodeFromMember(method, snippetWriter, codeGenContext.CodeGeneratorOptions); snippet = snippetWriter.GetStringBuilder(); } // Our convention above is that "_out_" will be replaced by the language-appropriate "out" parameter modifier. // In the case of VB, it is the default snippet.Replace("_out_", codeGenContext.IsCSharp ? "out " : string.Empty); // We need to indent the entire snippet 2 levels string indent = codeGenContext.CodeGeneratorOptions.IndentString; indent += indent; string snippetText = indent + snippet.ToString().Replace(Environment.NewLine, Environment.NewLine + indent).TrimEnd(' '); CodeSnippetTypeMember methodAsText = new CodeSnippetTypeMember(snippetText); return(methodAsText); }
/// <summary> /// Generates the update domain operation entry /// </summary> /// <param name="codeGenContext">The context to use</param> /// <param name="businessLogicClass">The business logic class into which to generate it</param> /// <param name="entity">The entity for which to generate the method</param> protected override void GenerateUpdateMethod(ICodeGenContext codeGenContext, CodeTypeDeclaration businessLogicClass, IBusinessLogicEntity entity) { string currentParameterName = "current" + entity.ClrType.Name; // public void Update$EntityName$($entityType$ current) CodeMemberMethod method = new CodeMemberMethod(); businessLogicClass.Members.Add(method); //LinqToEntitiesEntity efEntity = (LinqToEntitiesEntity)entity; method.Name = "Update" + CodeGenUtilities.MakeLegalEntityName(entity.Name); method.Attributes = MemberAttributes.Public | MemberAttributes.Final; // final needed to prevent virtual // parameter declaration method.Parameters.Add(new CodeParameterDeclarationExpression(entity.ClrType.Name, currentParameterName)); LinqToEntitiesEntity efEntity = (LinqToEntitiesEntity)entity; if (!efEntity.HasTimestampMember) { // this.ChangeSet.GetOriginal(current) CodeExpression changeSetRef = new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "ChangeSet"); CodeMethodReferenceExpression getOrigMethodRef = new CodeMethodReferenceExpression(changeSetRef, "GetOriginal"); CodeMethodInvokeExpression changeSetGetOrig = new CodeMethodInvokeExpression(getOrigMethodRef, new CodeArgumentReferenceExpression(currentParameterName)); // this.DbContext.$ObjectSetName$.AttachAsModified($current$, this.ChangeSet.GetOriginal(current), this.DbContext); CodeExpression contextRef = new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "DbContext"); CodePropertyReferenceExpression objectSetRef = new CodePropertyReferenceExpression(contextRef, efEntity.DefaultObjectSetName); CodeMethodInvokeExpression attachCall = new CodeMethodInvokeExpression(objectSetRef, "AttachAsModified", new CodeArgumentReferenceExpression(currentParameterName), changeSetGetOrig, new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "DbContext")); CodeExpressionStatement attachStmt = new CodeExpressionStatement(attachCall); method.Statements.Add(attachStmt); } else { // this.DbContext.$ObjectSetName$.AttachAsModified($current$, this.DbContext); CodeExpression contextRef = new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "DbContext"); CodePropertyReferenceExpression objectSetRef = new CodePropertyReferenceExpression(contextRef, efEntity.DefaultObjectSetName); CodeMethodInvokeExpression attachCall = new CodeMethodInvokeExpression(objectSetRef, "AttachAsModified", new CodeArgumentReferenceExpression(currentParameterName), new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "DbContext")); CodeExpressionStatement attachStmt = new CodeExpressionStatement(attachCall); method.Statements.Add(attachStmt); } }
/// <summary> /// Generates the metadata classes for all entities for the current context. /// </summary> /// <param name="codeGenContext">The context to use to generate code.</param> /// <param name="optionalSuffix">If nonblank, the suffix to append to namespace and class names for testing</param> /// <returns><c>true</c> means at least some code was generated.</returns> protected bool GenerateMetadataClasses(ICodeGenContext codeGenContext, string optionalSuffix) { bool generatedCode = false; if (this.NeedToGenerateMetadataClasses) { // Sort by entity name for baseline predictability foreach (BusinessLogicEntity entity in this.Entities.OrderBy(e => e.Name)) { if (entity.IsIncluded) { generatedCode |= this.GenerateMetadataClass(codeGenContext, optionalSuffix, entity.ClrType); generatedCode |= this.GenerateAdditionalMetadataClasses(codeGenContext, optionalSuffix, entity); } } } return generatedCode; }
/// <summary> /// Generates the delete domain operation entry /// </summary> /// <param name="codeGenContext">The context to use</param> /// <param name="businessLogicClass">The business logic class into which to generate it</param> /// <param name="entity">The entity for which to generate the method</param> protected override void GenerateDeleteMethod(ICodeGenContext codeGenContext, CodeTypeDeclaration businessLogicClass, IBusinessLogicEntity entity) { string parameterName = CodeGenUtilities.MakeLegalParameterName(entity.Name); // public void Delete$EntityName$($entityType$ $entityName$) CodeMemberMethod method = new CodeMemberMethod(); businessLogicClass.Members.Add(method); LinqToEntitiesEntity efDbEntity = (LinqToEntitiesEntity)entity; method.Name = "Delete" + CodeGenUtilities.MakeLegalEntityName(entity.Name); method.Attributes = MemberAttributes.Public | MemberAttributes.Final; // final needed to prevent virtual // parameter declaration method.Parameters.Add(new CodeParameterDeclarationExpression(entity.ClrType.Name, parameterName)); // Below we're generating the following method body // DbEntityEntry<$entityType$> entityEntry = this.DbContext.Entry($entity$); // if (entityEntry.State != EntityState.Detached) // { // entityEntry.State = EntityState.Deleted; // } // else // { // this.DbContext.$TablePropertyName$.Attach($entity$); // this.DbContext.$TablePropertyName$.Remove($entity$); // } CodeArgumentReferenceExpression entityArgRef = new CodeArgumentReferenceExpression(parameterName); CodeExpression contextRef = LinqToEntitiesDbContext.GetContextReferenceExpression(); CodeVariableDeclarationStatement entityEntryDeclaration = new CodeVariableDeclarationStatement( new CodeTypeReference("DbEntityEntry", new CodeTypeReference(entity.ClrType.Name)), "entityEntry", new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(contextRef, "Entry"), entityArgRef)); method.Statements.Add(entityEntryDeclaration); CodeVariableReferenceExpression entityEntryRef = new CodeVariableReferenceExpression("entityEntry"); CodePropertyReferenceExpression entityStateRef = new CodePropertyReferenceExpression(entityEntryRef, "State"); CodeFieldReferenceExpression detachedStateRef = new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(typeof(EntityState).Name), Enum.GetName(typeof(EntityState), EntityState.Deleted)); CodeExpression detachedStateTestExpr = CodeGenUtilities.MakeNotEqual(typeof(EntityState), entityStateRef, detachedStateRef, codeGenContext.IsCSharp); CodeFieldReferenceExpression deletedStateRef = new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(typeof(EntityState).Name), Enum.GetName(typeof(EntityState), EntityState.Deleted)); CodeAssignStatement deletedStateExpr = new CodeAssignStatement(entityStateRef, deletedStateRef); CodeMethodInvokeExpression attachedEntityMethodCall = new CodeMethodInvokeExpression(LinqToEntitiesDbContext.GetDbSetReferenceExpression(efDbEntity), "Attach", entityArgRef); CodeMethodInvokeExpression removedEntityMethodCall = new CodeMethodInvokeExpression(LinqToEntitiesDbContext.GetDbSetReferenceExpression(efDbEntity), "Remove", entityArgRef); CodeConditionStatement changeStateOrAddStmt = new CodeConditionStatement(detachedStateTestExpr, new CodeStatement[] { deletedStateExpr }, new CodeStatement[] { new CodeExpressionStatement(attachedEntityMethodCall), new CodeExpressionStatement(removedEntityMethodCall) }); method.Statements.Add(changeStateOrAddStmt); }
/// <summary> /// Generates the metadata class for the given object (entity or complex object) /// </summary> /// <param name="codeGenContext">The context to use to generate code.</param> /// <param name="optionalSuffix">If not null, optional suffix to class name and namespace</param> /// <param name="type">The type of the object for which to generate the metadata class.</param> /// <returns><c>true</c> means at least some code was generated.</returns> public bool GenerateMetadataClass(ICodeGenContext codeGenContext, string optionalSuffix, Type type) { // If already have a buddy class, bypass all this logic // Use soft dependency (string name) to avoid static dependency on DataAnnotations. // We do this because this wizard must run from the GAC, and DataAnnotations will not necessarily be in the GAC too. Type buddyClassType = TypeUtilities.GetAssociatedMetadataType(type); if (buddyClassType != null) { return false; } string className = type.Name; string classNamespace = type.Namespace; bool addSuffix = !string.IsNullOrEmpty(optionalSuffix); if (addSuffix) { className += optionalSuffix; classNamespace += optionalSuffix; } // Every object could have a unique namespace (odd, but true) // So we logically create a new namespace for each object. Those // sharing a namespace will reuse the CodeNamespace. // We allow the caller to specify in case it needs to override that // namespace. Unit testing is such a scenario CodeNamespace codeNamespace = codeGenContext.GetOrGenNamespace(classNamespace); // If we redirected to a different namespace than the object, import the real object's namespace if (addSuffix) { CodeGenUtilities.AddImportIfNeeded(codeNamespace, type.Namespace); } // Name of buddy class is $objectClassName$Metadata (e.g. Orders --> OrdersMetadata) string buddyClassName = className + "Metadata"; // We use the full outer.inner type naming convention for VB because they cannot resolve it otherwise. // C# can currently resolve it due to a bug in the compiler, but it is safer to use the legal syntax here. string fullBuddyClassName = className + "." + buddyClassName; CodeTypeDeclaration objectClass = null; // public class $objectType$ { } objectClass = CodeGenUtilities.CreateTypeDeclaration(className, classNamespace); objectClass.IsPartial = true; objectClass.TypeAttributes = TypeAttributes.Public; // Add explanatory comments about what the [MetadataTypeAttribute] does objectClass.Comments.Add(new CodeCommentStatement(String.Format(CultureInfo.CurrentCulture, Resources.BusinessLogicClass_Entity_Partial_Class_Remarks, buddyClassName, className), false)); // [MetadataType(typeof($objectType$.$objectType$_Metadata))] CodeAttributeDeclaration attr = CodeGenUtilities.CreateAttributeDeclaration(BusinessLogicClassConstants.MetadataTypeAttributeTypeName); CodeAttributeArgument attrArg = new CodeAttributeArgument(new CodeTypeOfExpression(fullBuddyClassName)); attr.Arguments.Add(attrArg); objectClass.CustomAttributes.Add(attr); // public sealed class $objectType$_Metadata { } // (note: cannot set 'static' modified from CodeDom.) CodeTypeDeclaration buddyClass = CodeGenUtilities.CreateTypeDeclaration(buddyClassName, classNamespace); // Both VB and C# use a friend/public buddy class. A private buddy class does not // compile in VB, and it compiles in C# only due to a bug. buddyClass.TypeAttributes = TypeAttributes.Sealed | TypeAttributes.NestedAssembly; bool generatedProperty = false; // Generate a developer comment describing what this class does buddyClass.Comments.Add(new CodeCommentStatement(String.Format(CultureInfo.CurrentCulture, Resources.Buddy_Class_Remarks, type.Name))); // Add a language-specific example string explanation = codeGenContext.IsCSharp ? Resources.Buddy_Class_Remarks_CSharp : Resources.Buddy_Class_Remarks_VB; buddyClass.Comments.Add(new CodeCommentStatement(explanation, false)); // Generate a private ctor to make it impossible to instantiate this class CodeConstructor ctor = new CodeConstructor(); ctor.Attributes = MemberAttributes.Private; ctor.Comments.Add(new CodeCommentStatement(Resources.BusinessLogicClass_Private_Ctor_Comment)); buddyClass.Members.Add(ctor); // Sort by name order for baseline predictability foreach (PropertyInfo propertyInfo in type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly).OrderBy(p => p.Name)) { // CodeDom does not support auto-implemented properties, so we will generate fields and then transform them into properties Type propType = propertyInfo.PropertyType; if (propType.IsVisible && propertyInfo.GetGetMethod() != null && this.CanGeneratePropertyOfType(propType)) { // Add an import for this property type's namespace if needed CodeGenUtilities.AddImportIfNeeded(codeNamespace, propertyInfo.PropertyType.Namespace); CodeSnippetTypeMember property = CodeGenUtilities.CreateAutomaticPropertyDeclaration(codeGenContext, buddyClass, propertyInfo, !string.IsNullOrEmpty(codeNamespace.Name) /* insideNamespace */); buddyClass.Members.Add(property); generatedProperty = true; } } // Don't generate anything if the buddy class is empty if (generatedProperty) { // Add the partial object class to the namespace codeNamespace.Types.Add(objectClass); // Add the metadata class as a nested class inside the partial object class objectClass.Members.Add(buddyClass); } // false if no properties were generated, indicating no code should be emitted return generatedProperty; }
internal CodeGen(ICodeGenContext context) { this.context = context; this.cg = context as ConstructorGen; il = context.GetILGenerator(); }
public CodeGen(ICodeGenContext context, bool isOwner = true) { _isOwner = isOwner; Context = context; #if !PHONE8 _cg = context as ConstructorGen; if (_cg != null && _cg.IsStatic) // #14 - cg is relevant for instance constructors - it wreaks havoc in a static constructor _cg = null; #endif IL = context.GetILGenerator(); }
/// <summary> /// Generates additional metadata classes for the given entity if necessary. /// </summary> /// <param name="codeGenContext">The context to use to generate code.</param> /// <param name="optionalSuffix">If not null, optional suffix to class name and namespace</param> /// <param name="entity">The entity for which to generate the additional metadata.</param> /// <returns><c>true</c> means at least some code was generated.</returns> /// <remarks> /// This default implementation of the virtual method does not generate any additional classes. It needs to be overridden in the derived /// classes to generate additional metadata classes if necessary. /// </remarks> protected virtual bool GenerateAdditionalMetadataClasses(ICodeGenContext codeGenContext, string optionalSuffix, BusinessLogicEntity entity) { return(false); }
/// <summary> /// Creates the "select" domain operation entry for the entity /// </summary> /// <remarks>This base class unconditionally returns <c>null</c> and should not be called by derived classes. /// This allows the base class to be used for the blank <see cref="DomainService"/>.</remarks> /// <param name="codeGenContext">The context into which to generate code. It cannot be null.</param> /// <param name="businessLogicClass">The class into which to generate the method</param> /// <param name="entity">The entity which will be affected by this method</param> /// <returns>The newly created method</returns> protected virtual CodeMemberMethod GenerateSelectMethod(ICodeGenContext codeGenContext, CodeTypeDeclaration businessLogicClass, IBusinessLogicEntity entity) { return(null); }
/// <summary> /// Generates the metadata class for the given object (entity or complex object) /// </summary> /// <param name="codeGenContext">The context to use to generate code.</param> /// <param name="optionalSuffix">If not null, optional suffix to class name and namespace</param> /// <param name="type">The type of the object for which to generate the metadata class.</param> /// <returns><c>true</c> means at least some code was generated.</returns> public bool GenerateMetadataClass(ICodeGenContext codeGenContext, string optionalSuffix, Type type) { // If already have a buddy class, bypass all this logic // Use soft dependency (string name) to avoid static dependency on DataAnnotations. // We do this because this wizard must run from the GAC, and DataAnnotations will not necessarily be in the GAC too. Type buddyClassType = TypeUtilities.GetAssociatedMetadataType(type); if (buddyClassType != null) { return(false); } string className = type.Name; string classNamespace = type.Namespace; bool addSuffix = !string.IsNullOrEmpty(optionalSuffix); if (addSuffix) { className += optionalSuffix; classNamespace += optionalSuffix; } // Every object could have a unique namespace (odd, but true) // So we logically create a new namespace for each object. Those // sharing a namespace will reuse the CodeNamespace. // We allow the caller to specify in case it needs to override that // namespace. Unit testing is such a scenario CodeNamespace codeNamespace = codeGenContext.GetOrGenNamespace(classNamespace); // If we redirected to a different namespace than the object, import the real object's namespace if (addSuffix) { CodeGenUtilities.AddImportIfNeeded(codeNamespace, type.Namespace); } // Name of buddy class is $objectClassName$Metadata (e.g. Orders --> OrdersMetadata) string buddyClassName = className + "Metadata"; // We use the full outer.inner type naming convention for VB because they cannot resolve it otherwise. // C# can currently resolve it due to a bug in the compiler, but it is safer to use the legal syntax here. string fullBuddyClassName = className + "." + buddyClassName; CodeTypeDeclaration objectClass = null; // public class $objectType$ { } objectClass = CodeGenUtilities.CreateTypeDeclaration(className, classNamespace); objectClass.IsPartial = true; objectClass.TypeAttributes = TypeAttributes.Public; // Add explanatory comments about what the [MetadataTypeAttribute] does objectClass.Comments.Add(new CodeCommentStatement(String.Format(CultureInfo.CurrentCulture, Resources.BusinessLogicClass_Entity_Partial_Class_Remarks, buddyClassName, className), false)); // [MetadataType(typeof($objectType$.$objectType$_Metadata))] CodeAttributeDeclaration attr = CodeGenUtilities.CreateAttributeDeclaration(BusinessLogicClassConstants.MetadataTypeAttributeTypeName); CodeAttributeArgument attrArg = new CodeAttributeArgument(new CodeTypeOfExpression(fullBuddyClassName)); attr.Arguments.Add(attrArg); objectClass.CustomAttributes.Add(attr); // public sealed class $objectType$_Metadata { } // (note: cannot set 'static' modified from CodeDom.) CodeTypeDeclaration buddyClass = CodeGenUtilities.CreateTypeDeclaration(buddyClassName, classNamespace); // Both VB and C# use a friend/public buddy class. A private buddy class does not // compile in VB, and it compiles in C# only due to a bug. buddyClass.TypeAttributes = TypeAttributes.Sealed | TypeAttributes.NestedAssembly; bool generatedProperty = false; // Generate a developer comment describing what this class does buddyClass.Comments.Add(new CodeCommentStatement(String.Format(CultureInfo.CurrentCulture, Resources.Buddy_Class_Remarks, type.Name))); // Add a language-specific example string explanation = codeGenContext.IsCSharp ? Resources.Buddy_Class_Remarks_CSharp : Resources.Buddy_Class_Remarks_VB; buddyClass.Comments.Add(new CodeCommentStatement(explanation, false)); // Generate a private ctor to make it impossible to instantiate this class CodeConstructor ctor = new CodeConstructor(); ctor.Attributes = MemberAttributes.Private; ctor.Comments.Add(new CodeCommentStatement(Resources.BusinessLogicClass_Private_Ctor_Comment)); buddyClass.Members.Add(ctor); // Sort by name order for baseline predictability foreach (PropertyInfo propertyInfo in type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly).OrderBy(p => p.Name)) { // CodeDom does not support auto-implemented properties, so we will generate fields and then transform them into properties Type propType = propertyInfo.PropertyType; if (propType.IsVisible && propertyInfo.GetGetMethod() != null && this.CanGeneratePropertyOfType(propType)) { // Add an import for this property type's namespace if needed CodeGenUtilities.AddImportIfNeeded(codeNamespace, propertyInfo.PropertyType.Namespace); CodeSnippetTypeMember property = CodeGenUtilities.CreateAutomaticPropertyDeclaration(codeGenContext, buddyClass, propertyInfo, !string.IsNullOrEmpty(codeNamespace.Name) /* insideNamespace */); buddyClass.Members.Add(property); generatedProperty = true; } } // Don't generate anything if the buddy class is empty if (generatedProperty) { // Add the partial object class to the namespace codeNamespace.Types.Add(objectClass); // Add the metadata class as a nested class inside the partial object class objectClass.Members.Add(buddyClass); } // false if no properties were generated, indicating no code should be emitted return(generatedProperty); }
public CodeGen(ICodeGenContext context) { this.context = context; this.cg = context as ConstructorGen; il = context.GetILGenerator(); }
/// <summary> /// Creates all the domain operation entries for the given entity. /// </summary> /// <param name="codeGenContext">The context into which to generate code. It cannot be null.</param> /// <param name="businessLogicClass">The class into which to generate the method</param> /// <param name="entity">The entity which will be affected by this method</param> public void GenerateEntityDomainOperationEntries(ICodeGenContext codeGenContext, CodeTypeDeclaration businessLogicClass, IBusinessLogicEntity entity) { CodeMemberMethod selectMethod = this.GenerateSelectMethod(codeGenContext, businessLogicClass, entity); if (selectMethod != null) { // If OData endpoint is requested, generate [Query(IsDefault=true)]. if (this.IsODataEndpointEnabled) { CodeAttributeDeclaration attributeDeclaration = new CodeAttributeDeclaration( new CodeTypeReference("Query"), new CodeAttributeArgument[] { new CodeAttributeArgument("IsDefault", new CodePrimitiveExpression(true)) }); selectMethod.CustomAttributes.Add(attributeDeclaration); } } if (entity.IsEditable) { this.GenerateInsertMethod(codeGenContext, businessLogicClass, entity); this.GenerateUpdateMethod(codeGenContext, businessLogicClass, entity); this.GenerateDeleteMethod(codeGenContext, businessLogicClass, entity); } }
/// <summary> /// Generates the select domain operation entry /// </summary> /// <param name="codeGenContext">The code gen context.></param> /// <param name="businessLogicClass">The business logic class.</param> /// <param name="entity">The entity.</param> /// <returns>The newly created method</returns> protected override CodeMemberMethod GenerateSelectMethod(ICodeGenContext codeGenContext, CodeTypeDeclaration businessLogicClass, IBusinessLogicEntity entity) { CodeMemberMethod method = null; LinqToSqlEntity ltsEntity = entity as LinqToSqlEntity; if (ltsEntity != null && ltsEntity.TablePropertyName != null) { // public IQueryable<$entityType$> GetEntities() method = new CodeMemberMethod(); businessLogicClass.Members.Add(method); // Add developer comment explaining they can add additional parameters method.Comments.Add(new CodeCommentStatement(Resources.BusinessLogicClass_Query_Method_Remarks, false)); method.Name = "Get" + CodeGenUtilities.MakeLegalEntityName(ltsEntity.TablePropertyName); method.ReturnType = new CodeTypeReference("IQueryable", new CodeTypeReference(entity.Name)); method.Attributes = MemberAttributes.Public | MemberAttributes.Final; // final needed to prevent virtual // return this.DataContext.$TablePropertyName$ CodeExpression contextExpr = new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "DataContext"); CodeExpression expr = new CodePropertyReferenceExpression(contextExpr, ltsEntity.TablePropertyName); CodeMethodReturnStatement returnStmt = new CodeMethodReturnStatement(expr); method.Statements.Add(returnStmt); } return method; }
/// <summary> /// Creates the "select" domain operation entry for the entity /// </summary> /// <remarks>This base class unconditionally returns <c>null</c> and should not be called by derived classes. /// This allows the base class to be used for the blank <see cref="DomainService"/>.</remarks> /// <param name="codeGenContext">The context into which to generate code. It cannot be null.</param> /// <param name="businessLogicClass">The class into which to generate the method</param> /// <param name="entity">The entity which will be affected by this method</param> /// <returns>The newly created method</returns> protected virtual CodeMemberMethod GenerateSelectMethod(ICodeGenContext codeGenContext, CodeTypeDeclaration businessLogicClass, IBusinessLogicEntity entity) { return null; }
/// <summary> /// Generates the delete domain operation entry /// </summary> /// <param name="codeGenContext">The code gen context.></param> /// <param name="businessLogicClass">The business logic class.</param> /// <param name="entity">The entity.</param> protected override void GenerateDeleteMethod(ICodeGenContext codeGenContext, CodeTypeDeclaration businessLogicClass, IBusinessLogicEntity entity) { string parameterName = CodeGenUtilities.MakeLegalParameterName(entity.Name); // public void Delete$EntityName$($entityType$ $entityName$) CodeMemberMethod method = new CodeMemberMethod(); businessLogicClass.Members.Add(method); LinqToSqlEntity ltsEntity = (LinqToSqlEntity)entity; method.Name = "Delete" + CodeGenUtilities.MakeLegalEntityName(entity.Name); method.Attributes = MemberAttributes.Public | MemberAttributes.Final; // final needed to prevent virtual // parameter declaration method.Parameters.Add(new CodeParameterDeclarationExpression(entity.ClrType.Name, parameterName)); // this.DataContext.$TablePropertyName$.Attach(current) CodeExpression contextRef = new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "DataContext"); CodeExpression tableRef = new CodePropertyReferenceExpression(contextRef, ltsEntity.TablePropertyName); CodeMethodInvokeExpression attachCall = new CodeMethodInvokeExpression(tableRef, "Attach", new CodeArgumentReferenceExpression(parameterName)); method.Statements.Add(attachCall); // this.DataContext.$TablePropertyName$.DeleteOnSubmit(current) CodeMethodInvokeExpression deleteCall = new CodeMethodInvokeExpression(tableRef, "DeleteOnSubmit", new CodeArgumentReferenceExpression(parameterName)); method.Statements.Add(deleteCall); }
/// <summary> /// Creates the "delete" method for the entity /// </summary> /// <param name="codeGenContext">The context into which to generate code. It cannot be null.</param> /// <param name="businessLogicClass">The class into which to generate the method</param> /// <param name="entity">The entity which will be affected by this method</param> protected virtual void GenerateDeleteMethod(ICodeGenContext codeGenContext, CodeTypeDeclaration businessLogicClass, IBusinessLogicEntity entity) { }
/// <summary> /// Creates a property declaration for buddy class. /// </summary> /// <param name="codeGenContext">Gode generation context.</param> /// <param name="buddyClass"><see cref="CodeTypeDeclaration"/> for a buddy class.</param> /// <param name="propertyInfo"><see cref="PropertyInfo"/> for the original property.</param> /// <param name="insideNamespace">Whether or not our buddy class is inside a namespace.</param> /// <returns>A code snippet for a buddy property.</returns> public static CodeSnippetTypeMember CreateAutomaticPropertyDeclaration(ICodeGenContext codeGenContext, CodeTypeDeclaration buddyClass, PropertyInfo propertyInfo, bool insideNamespace) { // Create a field declaration: public static $propertyType$ $propertyName; CodeTypeReference propTypeRef = CodeGenUtilities.GetTypeReference(propertyInfo.PropertyType, codeGenContext, buddyClass); CodeMemberField field = new CodeMemberField(propTypeRef, propertyInfo.Name); field.Attributes = MemberAttributes.Public; CodeSnippetTypeMember property = null; CodeGeneratorOptions codeGeneratorOptions = codeGenContext.CodeGeneratorOptions; using (StringWriter stringWriter = new StringWriter(System.Globalization.CultureInfo.InvariantCulture)) { // create a StringBuilder with correct identation (we expect identation to stay constant) string indentString = codeGeneratorOptions.IndentString; StringBuilder stringBuilder = new StringBuilder(indentString); stringBuilder.Append(indentString); // If we're inside an namespace increase indent (in VB there's usually no explicit namespace) if (insideNamespace) { stringBuilder.Append(indentString); } // generate the code for a field codeGenContext.Provider.GenerateCodeFromMember(field, stringWriter, codeGenContext.CodeGeneratorOptions); stringBuilder.Append(stringWriter.GetStringBuilder()); stringBuilder.Replace(Environment.NewLine, String.Empty); // do a manual replace to transform a field into a property if (codeGenContext.IsCSharp) { stringBuilder.Replace(";", " { get; set; }"); } else { // typical VB code gen looks like: Public MyName As Integer // insert 'Property' between 'Public' and 'MyName' int propertyTokenPosition = stringBuilder.ToString().IndexOf("Public", StringComparison.Ordinal) + "Public".Length; stringBuilder.Insert(propertyTokenPosition, " Property"); } // create a code snippet out of resulting code property = new CodeSnippetTypeMember(stringBuilder.ToString()); } return property; }