# Licensed under the MIT License (MIT) import os import sys import xml.etree.ElementTree as ET INDENT = "\t" NEWLINE = "\n" OUTPUT_PATH = "../OrmFactoryCom/Model/DataContextGenerated.cs" NAMESPACE = "OrmFactoryCom.Model" CONTEXT_NAME = "DataContext" def is_database_generated(column: ET.Element): default_value = column.get("Default") return default_value == "current_timestamp()" def resolve_type(db_type: str) -> str: if db_type.startswith("tinyint(1)"): return "bool" if any(db_type.startswith(t) for t in ["tinyint", "smallint", "mediumint", "int"]): if "unsigned" in db_type: return "uint" return "int" if db_type.startswith("bigint"): if "unsigned" in db_type: return "ulong" return "long" if any(db_type.startswith(t) for t in ["timestamp", "datetime"]): return "DateTime" if any(db_type.startswith(t) for t in ["varchar", "char", "tinytext", "mediumtext", "text", "longtext", "set", "enum", "geometry"]): return "string" if db_type.startswith("year"): return "int" if db_type.startswith("date"): return "DateOnly" if db_type.startswith("decimal"): return "decimal" if db_type.startswith("blob"): return "byte[]" raise ValueError(f"Unknown type: {db_type}") def resolve_type_from_column(column: ET.Element) -> str: db_type = column.get("DatabaseType").lower() nullable = column.get("Nullable", "false").lower() == "true" resolved_type = resolve_type(db_type) if nullable: return resolved_type + "?" return resolved_type def get_class_lines(table: ET.Element): table_name = table.get("Name") class_name = table.get("ClassName") table_comment = table.get("Comment") yield "" if table_comment: yield f"/// " yield f"///{table_comment}" yield f"/// " #if table_name != class_name: yield f"[Table(\"{table_name}\")]" yield f"public partial class {class_name}" yield "{" columns_dict = {} for column in table.findall("Column"): column_name = column.get("Name") field_name = column.get("FieldName") comment = column.get("Comment") columns_dict[column_name] = column if comment: yield f"{INDENT}/// " yield f"{INDENT}///{comment}" yield f"{INDENT}/// " if column.get("PrimaryKey"): yield f"{INDENT}[Key]" elif is_database_generated(column): yield f"{INDENT}[DatabaseGenerated(DatabaseGeneratedOption.Computed)]" if column_name != field_name: yield f"{INDENT}[Column(\"{column_name}\")]" csharp_type = resolve_type_from_column(column) yield f"{INDENT}public {csharp_type} {field_name} {{ get; set; }}" for fk in table.findall("ForeignKey"): from_col = fk.get('FromColumn') field_name = fk.get('FieldName') class_type = fk.get('ToClassName') from_column = columns_dict[from_col] from_field_name = from_column.get("FieldName") is_nullable = from_column.get("Nullable", "false").lower() == "true" yield f"{INDENT}[ForeignKey(\"{from_field_name}\")]" if is_nullable: class_type = class_type + "?" yield f"{INDENT}public {class_type} {field_name} {{ get; set; }}" yield "}" xml_data = sys.stdin.read() tree = ET.ElementTree(ET.fromstring(xml_data)) root = tree.getroot() output_file = os.path.abspath(OUTPUT_PATH) dbsets = [] classes = [] for db in root.findall('Database'): for schema in db.findall('Schema'): for table in schema.findall('Table'): class_name = table.get("ClassName") repository_name = table.get("RepositoryName") dbsets.append(f"{INDENT}public DbSet<{class_name}> {repository_name} {{ get; set; }}") classes.extend(get_class_lines(table)) content_lines = [ "using System;", "using System.ComponentModel.DataAnnotations;", "using System.ComponentModel.DataAnnotations.Schema;", "using Microsoft.EntityFrameworkCore;", "", f"namespace {NAMESPACE};", "", f"public partial class {CONTEXT_NAME} : DbContext", "{"] content_lines.extend(dbsets) content_lines.append("}") content_lines.extend(classes) content = NEWLINE.join(content_lines) with open(output_file, "w", encoding="utf-8", newline=NEWLINE) as f: f.write(content)