/// <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); }
public void RunStarted(object automationObject, Dictionary <string, string> replacementsDictionary, WizardRunKind runKind, object[] customParams) { // This instance may be reused -- reinitialize each time this._project = null; this._dte2 = automationObject as DTE2; if (this._dte2 == null) { this.TerminateWizard(Resources.WizardError_No_DTE); } // Get active project. Throws if null. Project project = this.ActiveProject; ITypeDiscoveryService typeDiscoveryService = this.GetTypeDiscoveryService(project); if (typeDiscoveryService == null) { this.TerminateWizard(Resources.BusinessLogicClass_Error_No_TypeDiscoveryService); } // Check if the project has a reference to the assembly that has DbDomainService, supporting DbContext. VSProject vsproj = project.Object as VSProject; bool allowDbContext = false; if (vsproj != null) { allowDbContext = vsproj.References.Cast <Reference>().Any(r => String.Equals(r.Name, BusinessLogicClassConstants.DbDomainServiceAssemblyShortName)); } // Get the list of available ObjectContexts, DataContexts, and optionally DbContexts. bool foundDbContext = false; IEnumerable <Type> candidates = this.GetCandidateTypes(typeDiscoveryService, allowDbContext, out foundDbContext); // Ensure the user entered a non-null file name string fileName = replacementsDictionary["$rootname$"]; fileName = fileName.Trim(); if (string.IsNullOrEmpty(fileName)) { this.TerminateWizard(Resources.WizardError_Empty_Filename); } // Class name is file name minus extension. Validate not empty. string className = Path.GetFileNameWithoutExtension(fileName); if (string.IsNullOrEmpty(className)) { this.TerminateWizard(Resources.WizardError_Empty_Filename); } // We infer language from extension string extension = Path.GetExtension(fileName); bool isVb = extension.EndsWith("vb", StringComparison.OrdinalIgnoreCase); string language = isVb ? "VB" : "C#"; Property rootNamespaceProperty = project.Properties.Item("RootNamespace"); string namespaceName = rootNamespaceProperty == null ? null : (string)(rootNamespaceProperty.Value); if (string.IsNullOrEmpty(namespaceName)) { this.TerminateWizard(Resources.BusinessLogicClass_Error_No_RootNamespace); } // Extract VB root namespace for code gen. // If non-empty, it means we want to avoid generating namespaces that begin with it. string rootNamespace = isVb ? namespaceName : string.Empty; // Get the name of the assembly produced by the current project Property assemblyNameProperty = project.Properties.Item("AssemblyName"); string assemblyName = assemblyNameProperty == null ? null : (string)(assemblyNameProperty.Value); if (string.IsNullOrEmpty(assemblyName)) { this.TerminateWizard(Resources.BusinessLogicClass_Error_No_AssemblyName); } // We extract all the context types from the TypeDiscovery service and will pass // those to another AppDomain for analysis IEnumerable <Type> candidateTypes = candidates.Where(t => CodeGenUtilities.IsValidGenericTypeParam(t)); // We need the project path for the ClientBuildManager source folder string projectPath = project.FullName; if (string.IsNullOrEmpty(projectPath)) { this.TerminateWizard(Resources.BusinessLogicClass_No_Project_Path); } string projectDirectory = Path.GetDirectoryName(projectPath); try { IVsHelp help = this.GetService(typeof(IVsHelp)) as IVsHelp; // Strategy: we instantiate the contexts in another AppDomain so they can load the assembly outside of the current // Visual Studio root AppDomain. The main reason for this is the ability to reopen the DSWizard onto modified // client assemblies and see modified types. If they were loaded into the root AppDomain, we would not be able to // reload. The BusinessLogicViewModel is IDisposable and controls the other AppDomain's lifetime. using (BusinessLogicViewModel businessLogicViewModel = new BusinessLogicViewModel(projectDirectory, className, language, rootNamespace, assemblyName, candidateTypes, help)) { businessLogicViewModel.ShowDbContextWarning = false; // foundDbContext; //Removed by CDB //TODO: remove commented out section // Intercept exceptions to report to VS UI. businessLogicViewModel.ExceptionHandler = delegate(Exception ex) { this.ShowError(ex.Message); throw ex; }; // Invoke the wizard UI now this._dialog = new BusinessLogicClassDialog(); this._dialog.Model = businessLogicViewModel; IVsUIShell uiShell = this.GetService(typeof(IVsUIShell)) as IVsUIShell; IntPtr dialogOwnerHwnd = default(IntPtr); int result = uiShell.GetDialogOwnerHwnd(out dialogOwnerHwnd); if (result == 0 && dialogOwnerHwnd != default(IntPtr)) { WindowInteropHelper windowHelper = new WindowInteropHelper(this._dialog); windowHelper.Owner = dialogOwnerHwnd; } this._dialog.ShowInTaskbar = false; this._dialog.ShowDialog(); bool success = this._dialog.DialogResult.HasValue && this._dialog.DialogResult.Value; this._dialog.Model = null; // If user cancels dialog, cancel wizard if (!success) { throw new WizardCancelledException(); } // Capture some model state to we can dispose the contexts and models ContextViewModel currentContext = businessLogicViewModel.CurrentContextViewModel; this._isClientAccessEnabled = currentContext != null && currentContext.IsClientAccessEnabled; this._isODataEndpointEnabled = currentContext != null && currentContext.IsODataEndpointEnabled; // Compute a namespace that includes folder names namespaceName = this.ComputeNamespace(); // User said OK -- so let's generate the code IGeneratedCode generatedCode = businessLogicViewModel.GenerateBusinessLogicClass(namespaceName); replacementsDictionary.Add("$generatedcode$", generatedCode.SourceCode); this.AddReferences(generatedCode.References); this._businessLogicCode = generatedCode; // If user elected metadata classes, do that into a separate file if (businessLogicViewModel.IsMetadataClassGenerationRequested) { // The null namespace asks to generate into the entity types own namespaces IGeneratedCode generatedMetadataCode = businessLogicViewModel.GenerateMetadataClasses(null /* optionalSuffix */); replacementsDictionary.Add("$generatedmetadatacode$", generatedMetadataCode.SourceCode); this.AddReferences(generatedMetadataCode.References); this._generateMetadataFile = generatedMetadataCode.SourceCode.Length > 0; this._metadataCode = generatedMetadataCode; } else { this._generateMetadataFile = false; } } } finally { this._dialog = null; } }
/// <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); }