private static CodeMemberProperty GenerateCatalogTableProperty(DataTable dataTable)
        {
            CodeMemberProperty propDecl = new CodeMemberProperty();

            propDecl.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            propDecl.Name       = GetCatalogTablePropertyName(dataTable);
            propDecl.HasGet     = true;
            propDecl.HasSet     = true;

            propDecl.Type = new CodeTypeReference(typeof(DbSet <>));
            propDecl.Type.TypeArguments.Add(new CodeTypeReference(CatalogTableTypeGenerator.GetTypeName(dataTable)));

            propDecl.GetStatements.Add(
                new CodeMethodReturnStatement(
                    new CodeFieldReferenceExpression(
                        new CodeThisReferenceExpression(), GetCatalogTableFieldName(dataTable))));

            propDecl.SetStatements.Add(
                new CodeAssignStatement(
                    new CodeFieldReferenceExpression(
                        new CodeThisReferenceExpression(),
                        GetCatalogTableFieldName(dataTable)),
                    new CodePropertySetValueReferenceExpression()));

            return(propDecl);
        }
        private static CodeMemberField GenerateCatalogTableField(DataTable dataTable)
        {
            CodeMemberField fieldDecl = new CodeMemberField();

            fieldDecl.Attributes = MemberAttributes.Private;
            fieldDecl.Name       = GetCatalogTableFieldName(dataTable);
            fieldDecl.Type       = new CodeTypeReference(typeof(DbSet <>));
            fieldDecl.Type.TypeArguments.Add(new CodeTypeReference(CatalogTableTypeGenerator.GetTypeName(dataTable)));

            return(fieldDecl);
        }
        public void Generate(List <CatalogVersion> catalogVersions, string outputFolder)
        {
            foreach (CatalogVersion catalogVersion in catalogVersions)
            {
                Console.WriteLine("Loading catalog xml file {0}...", catalogVersion.XmlFile);
                catalogVersion.LoadCatalogDataSetFromXml();
            }

            Console.WriteLine("Merging catalog xml files...");
            DataSet mergedDataSet = this.MergeDataSet(catalogVersions);

            List <CodeTypeDeclaration> typeDecls = new List <CodeTypeDeclaration>();

            Console.WriteLine("Generating type {0}...", "DatabaseCatalogContext");
            DatabaseCatalogTypeGenerator databaseCatalogTypeGenerator = new DatabaseCatalogTypeGenerator(mergedDataSet, catalogVersions);

            typeDecls.Add(databaseCatalogTypeGenerator.Generate());

            foreach (DataTable dataTable in databaseCatalogTypeGenerator.MergeDataSet.Tables)
            {
                Console.WriteLine("Generating type {0}...", dataTable.TableName);
                CatalogTableTypeGenerator catalogTypeGenerator = new CatalogTableTypeGenerator(dataTable);
                CodeTypeDeclaration       catalogTypeDecl      = catalogTypeGenerator.Generate();
                typeDecls.Add(catalogTypeDecl);
            }

            Console.WriteLine("Writing code files...");
            foreach (CodeTypeDeclaration typeDecl in typeDecls)
            {
                CodeNamespace namespaceDecl = new CodeNamespace("Microsoft.SqlServer.CatalogStore");
                namespaceDecl.Imports.Add(new CodeNamespaceImport("System"));
                namespaceDecl.Imports.Add(new CodeNamespaceImport("System.Data.SqlClient"));
                namespaceDecl.Imports.Add(new CodeNamespaceImport("Microsoft.Data.Sqlite"));
                namespaceDecl.Imports.Add(new CodeNamespaceImport("Microsoft.EntityFrameworkCore"));
                namespaceDecl.Types.Add(typeDecl);

                WriteToFile(namespaceDecl, outputFolder + Path.DirectorySeparatorChar + typeDecl.Name + ".g.cs");
            }
        }
        private CodeMemberMethod GenerateLoadMethod(CatalogVersion catalogVersion)
        {
            CodeMemberMethod methodDecl = new CodeMemberMethod();

            methodDecl.Name       = "Load" + catalogVersion.ReleaseName;
            methodDecl.Attributes = MemberAttributes.Private | MemberAttributes.Final;
            methodDecl.Parameters.Add(new CodeParameterDeclarationExpression(typeof(SqlConnection), "connection"));

            methodDecl.Statements.Add(
                new CodeVariableDeclarationStatement(
                    typeof(SqlCommand),
                    "command",
                    new CodePrimitiveExpression(null)));

            methodDecl.Statements.Add(
                new CodeVariableDeclarationStatement(
                    typeof(SqlDataReader),
                    "reader",
                    new CodePrimitiveExpression(null)));

            CodeTryCatchFinallyStatement tcfStatement = new CodeTryCatchFinallyStatement();

            string sql = string.Join(";", catalogVersion.CatalogDataSet.Tables.OfType <DataTable>().Select(dt => "select * from " + dt.TableName));

            tcfStatement.TryStatements.Add(
                new CodeAssignStatement(
                    new CodeVariableReferenceExpression("command"),
                    new CodeObjectCreateExpression(typeof(SqlCommand), new CodePrimitiveExpression(sql))));

            tcfStatement.TryStatements.Add(
                new CodeAssignStatement(
                    new CodePropertyReferenceExpression(new CodeVariableReferenceExpression("command"), "Connection"),
                    new CodeVariableReferenceExpression("connection")));

            tcfStatement.TryStatements.Add(
                new CodeAssignStatement(
                    new CodeVariableReferenceExpression("reader"),
                    new CodeMethodInvokeExpression(
                        new CodeVariableReferenceExpression("command"),
                        "ExecuteReader")));

            foreach (DataTable dataTable in catalogVersion.CatalogDataSet.Tables)
            {
                CodeConditionStatement hasRowsConditionStatement = new CodeConditionStatement();
                hasRowsConditionStatement.Condition = new CodePropertyReferenceExpression(new CodeVariableReferenceExpression("reader"), "HasRows");

                hasRowsConditionStatement.TrueStatements.Add(
                    new CodeVariableDeclarationStatement(
                        typeof(object[]),
                        "values",
                        new CodeArrayCreateExpression(
                            typeof(object),
                            new CodePropertyReferenceExpression(new CodeVariableReferenceExpression("reader"), "FieldCount"))));

                hasRowsConditionStatement.TrueStatements.Add(
                    new CodeVariableDeclarationStatement(
                        typeof(SqliteTransaction),
                        "sqliteTransaction",
                        new CodeMethodInvokeExpression(
                            new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "_sqliteConnection"),
                            "BeginTransaction")));

                hasRowsConditionStatement.TrueStatements.Add(
                    new CodeVariableDeclarationStatement(
                        typeof(SqliteCommand),
                        "sqliteCommand",
                        new CodeMethodInvokeExpression(
                            new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "_sqliteConnection"),
                            "CreateCommand")));

                List <string> insertColumns = new List <string>();
                List <string> columns       = new List <string>();
                foreach (DataRow dataRow in dataTable.Rows)
                {
                    insertColumns.Add((string)dataRow["ColumnName"]);
                    columns.Add("@" + CatalogTableTypeGenerator.GetVariableName(dataRow));
                }

                StringBuilder sb = new StringBuilder();
                sb.AppendFormat("insert into {0} ({1}) values (", dataTable.TableName.Replace(".", "_"), string.Join(",", insertColumns));

                sb.Append(string.Join(", ", columns));
                sb.Append(")");

                hasRowsConditionStatement.TrueStatements.Add(
                    new CodeAssignStatement(
                        new CodePropertyReferenceExpression(
                            new CodeVariableReferenceExpression("sqliteCommand"),
                            "CommandText"),
                        new CodePrimitiveExpression(sb.ToString())));

                hasRowsConditionStatement.TrueStatements.Add(new CodeSnippetStatement());

                foreach (DataRow dataRow in dataTable.Rows)
                {
                    Type   dataRowType = (Type)dataRow["DataType"];
                    DbType dbType;
                    if (!_dbTypeMap.TryGetValue(dataRowType, out dbType))
                    {
                        throw new NotSupportedException(string.Format("Data row type {0} is not mapped to a System.Data.DbType.", dataRowType.FullName));
                    }

                    hasRowsConditionStatement.TrueStatements.Add(
                        new CodeVariableDeclarationStatement(
                            typeof(SqliteParameter),
                            CatalogTableTypeGenerator.GetVariableName(dataRow),
                            new CodeObjectCreateExpression(
                                typeof(SqliteParameter),
                                new CodePrimitiveExpression("@" + CatalogTableTypeGenerator.GetVariableName(dataRow)),
                                new CodeFieldReferenceExpression(
                                    new CodeTypeReferenceExpression(typeof(DbType)),
                                    dbType.ToString()))));

                    hasRowsConditionStatement.TrueStatements.Add(
                        new CodeMethodInvokeExpression(
                            new CodePropertyReferenceExpression(
                                new CodeVariableReferenceExpression("sqliteCommand"),
                                "Parameters"),
                            "Add",
                            new CodeVariableReferenceExpression(CatalogTableTypeGenerator.GetVariableName(dataRow))));
                }

                hasRowsConditionStatement.TrueStatements.Add(
                    new CodeMethodInvokeExpression(
                        new CodeVariableReferenceExpression("sqliteCommand"),
                        "Prepare"));

                hasRowsConditionStatement.TrueStatements.Add(new CodeSnippetStatement());

                CodeIterationStatement readLoopStmt = new CodeIterationStatement(
                    new CodeSnippetStatement(),
                    new CodeMethodInvokeExpression(new CodeVariableReferenceExpression("reader"), "Read"),
                    new CodeSnippetStatement());

                readLoopStmt.Statements.Add(
                    new CodeMethodInvokeExpression(
                        new CodeVariableReferenceExpression("reader"),
                        "GetValues",
                        new CodeVariableReferenceExpression("values")));

                readLoopStmt.Statements.Add(new CodeSnippetStatement());

                foreach (DataRow dataRow in dataTable.Rows)
                {
                    readLoopStmt.Statements.Add(
                        new CodeAssignStatement(
                            new CodePropertyReferenceExpression(
                                new CodeVariableReferenceExpression(CatalogTableTypeGenerator.GetVariableName(dataRow)),
                                "Value"),
                            new CodeArrayIndexerExpression(
                                new CodeVariableReferenceExpression("values"),
                                new CodePrimitiveExpression(dataRow["ColumnOrdinal"]))));
                }

                readLoopStmt.Statements.Add(new CodeSnippetStatement());

                readLoopStmt.Statements.Add(
                    new CodeMethodInvokeExpression(
                        new CodeVariableReferenceExpression("sqliteCommand"), "ExecuteNonQuery"));

                hasRowsConditionStatement.TrueStatements.Add(readLoopStmt);

                hasRowsConditionStatement.TrueStatements.Add(
                    new CodeMethodInvokeExpression(
                        new CodeVariableReferenceExpression("sqliteCommand"), "Dispose"));

                hasRowsConditionStatement.TrueStatements.Add(
                    new CodeMethodInvokeExpression(
                        new CodeVariableReferenceExpression("sqliteTransaction"), "Commit"));

                tcfStatement.TryStatements.Add(hasRowsConditionStatement);
                tcfStatement.TryStatements.Add(new CodeSnippetStatement());

                tcfStatement.TryStatements.Add(
                    new CodeMethodInvokeExpression(
                        new CodeVariableReferenceExpression("reader"), "NextResult"));
            }

            tcfStatement.FinallyStatements.Add(
                new CodeConditionStatement(
                    new CodeBinaryOperatorExpression(
                        new CodeVariableReferenceExpression("reader"),
                        CodeBinaryOperatorType.IdentityInequality,
                        new CodePrimitiveExpression(null)),
                    new CodeExpressionStatement(
                        new CodeMethodInvokeExpression(
                            new CodeVariableReferenceExpression("reader"),
                            "Dispose"))));

            tcfStatement.FinallyStatements.Add(
                new CodeConditionStatement(
                    new CodeBinaryOperatorExpression(
                        new CodeVariableReferenceExpression("command"),
                        CodeBinaryOperatorType.IdentityInequality,
                        new CodePrimitiveExpression(null)),
                    new CodeExpressionStatement(
                        new CodeMethodInvokeExpression(
                            new CodeVariableReferenceExpression("command"),
                            "Dispose"))));

            methodDecl.Statements.Add(tcfStatement);

            methodDecl.Statements.Add(
                new CodeMethodInvokeExpression(
                    new CodeThisReferenceExpression(),
                    "SetupSqliteFunctions"));

            return(methodDecl);
        }