public SourceText GetInputTextForStoredProcedure(Definition.Schema schema, Definition.StoredProcedure storedProcedure) { var rootDir = _output.GetOutputRootDir(); var fileContent = File.ReadAllText(Path.Combine(rootDir.FullName, "DataContext", "Inputs", "Input.cs")); var tree = CSharpSyntaxTree.ParseText(fileContent); var root = tree.GetCompilationUnitRoot(); // If Inputs contains a TableType, add using for TableTypes var schemesForTableTypes = storedProcedure.Input.Where(i => i.IsTableType ?? false) .GroupBy(t => (t.TableTypeSchemaName, t.TableTypeName), (key, group) => new { TableTypeSchemaName = key.TableTypeSchemaName, Result = group.First() }).Select(g => g.Result).ToList(); var tableTypeSchemas = storedProcedure.Input.Where(i => i.IsTableType ?? false) .GroupBy(t => t.TableTypeSchemaName, (key, group) => key).ToList(); foreach (var tableTypeSchema in tableTypeSchemas) { var tableTypeSchemaConfig = _configFile.Config.Schema.Find(s => s.Name.Equals(tableTypeSchema)); // is schema of table type ignored and its an extension? var useFromLib = tableTypeSchemaConfig?.Status != SchemaStatusEnum.Build && _configFile.Config.Project.Role.Kind == ERoleKind.Extension; var paramUsingDirective = useFromLib ? SyntaxFactory.UsingDirective(SyntaxFactory.ParseName($"{_configFile.Config.Project.Role.LibNamespace}.TableTypes.{tableTypeSchema.FirstCharToUpper()}")) : _configFile.Config.Project.Role.Kind == ERoleKind.Lib ? SyntaxFactory.UsingDirective(SyntaxFactory.ParseName($"{_configFile.Config.Project.Output.Namespace}.TableTypes.{tableTypeSchema.FirstCharToUpper()}")) : SyntaxFactory.UsingDirective(SyntaxFactory.ParseName($"{_configFile.Config.Project.Output.Namespace}.DataContext.TableTypes.{tableTypeSchema.FirstCharToUpper()}")); root = root.AddUsings(paramUsingDirective); } // Replace Namespace if (_configFile.Config.Project.Role.Kind == ERoleKind.Lib) { root = root.ReplaceNamespace(ns => ns.Replace("Source.DataContext", _configFile.Config.Project.Output.Namespace).Replace("Schema", schema.Name)); } else { root = root.ReplaceNamespace(ns => ns.Replace("Source", _configFile.Config.Project.Output.Namespace).Replace("Schema", schema.Name)); } // Replace ClassName root = root.ReplaceClassName(ci => ci.Replace("Input", $"{storedProcedure.Name}Input")); var nsNode = (NamespaceDeclarationSyntax)root.Members[0]; var classNode = (ClassDeclarationSyntax)nsNode.Members[0]; // Create obsolete constructor var obsoleteContructor = classNode.CreateConstructor($"{storedProcedure.Name}Input"); root = root.AddObsoleteAttribute(ref obsoleteContructor, "This empty contructor will be removed in vNext. Please use constructor with parameters."); root = root.AddConstructor(ref classNode, obsoleteContructor); nsNode = (NamespaceDeclarationSyntax)root.Members[0]; classNode = (ClassDeclarationSyntax)nsNode.Members[0]; var inputs = storedProcedure.Input.Where(i => !i.IsOutput).ToList(); // Constructor with params var constructor = classNode.CreateConstructor($"{storedProcedure.Name}Input"); var parameters = inputs.Select(input => { return(SyntaxFactory.Parameter(SyntaxFactory.Identifier(GetIdentifierFromSqlInputTableType(input.Name))) .WithType( input.IsTableType ?? false ? GetTypeSyntaxForTableType(input) : ParseTypeFromSqlDbTypeName(input.SqlTypeName, input.IsNullable ?? false) )); }).ToArray(); var constructorParams = constructor.ParameterList.AddParameters(parameters); constructor = constructor.WithParameterList(constructorParams); foreach (var input in inputs) { var constructorStatement = ExpressionHelper.AssignmentStatement(TokenHelper.Parse(input.Name).ToString(), GetIdentifierFromSqlInputTableType(input.Name)); var newStatements = constructor.Body.Statements.Add(constructorStatement); constructor = constructor.WithBody(constructor.Body.WithStatements(newStatements)); } root = root.AddConstructor(ref classNode, constructor); nsNode = (NamespaceDeclarationSyntax)root.Members[0]; classNode = (ClassDeclarationSyntax)nsNode.Members[0]; // Generate Properies // https://stackoverflow.com/questions/45160694/adding-new-field-declaration-to-class-with-roslyn foreach (var item in storedProcedure.Input) { nsNode = (NamespaceDeclarationSyntax)root.Members[0]; classNode = (ClassDeclarationSyntax)nsNode.Members[0]; var isTableType = item.IsTableType ?? false; var propertyType = isTableType ? GetTypeSyntaxForTableType(item) : ParseTypeFromSqlDbTypeName(item.SqlTypeName, item.IsNullable ?? false); var propertyNode = classNode.CreateProperty(propertyType, item.Name); if (!isTableType) { // Add Attribute for NVARCHAR with MaxLength if ((item.SqlTypeName?.Equals(SqlDbType.NVarChar.ToString(), StringComparison.InvariantCultureIgnoreCase) ?? false) && item.MaxLength.HasValue) { var attributes = propertyNode.AttributeLists.Add( SyntaxFactory.AttributeList(SyntaxFactory.SingletonSeparatedList <AttributeSyntax>( SyntaxFactory.Attribute(SyntaxFactory.IdentifierName("MaxLength"), SyntaxFactory.ParseAttributeArgumentList($"({item.MaxLength})")) )).NormalizeWhitespace()); propertyNode = propertyNode.WithAttributeLists(attributes); } } root = root.AddProperty(ref classNode, propertyNode); } return(root.NormalizeWhitespace().GetText()); }