How can I generate database tables from C# classes?

前端 未结 12 1450
谎友^
谎友^ 2020-12-02 05:26

Does anyone know a way to auto-generate database tables for a given class? I\'m not looking for an entire persistence layer - I already have a data access solution I\'m usi

12条回答
  •  执笔经年
    2020-12-02 06:24

    It's really late, and I only spent about 10 minutes on this, so its extremely sloppy, however it does work and will give you a good jumping off point:

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Reflection;
    
    namespace TableGenerator
    {
        class Program
        {
            static void Main(string[] args)
            {
                List tables = new List();
    
                // Pass assembly name via argument
                Assembly a = Assembly.LoadFile(args[0]);
    
                Type[] types = a.GetTypes();
    
                // Get Types in the assembly.
                foreach (Type t in types)
                {
                    TableClass tc = new TableClass(t);                
                    tables.Add(tc);
                }
    
                // Create SQL for each table
                foreach (TableClass table in tables)
                {
                    Console.WriteLine(table.CreateTableScript());
                    Console.WriteLine();
                }
    
                // Total Hacked way to find FK relationships! Too lazy to fix right now
                foreach (TableClass table in tables)
                {
                    foreach (KeyValuePair field in table.Fields)
                    {
                        foreach (TableClass t2 in tables)
                        {
                            if (field.Value.Name == t2.ClassName)
                            {
                                // We have a FK Relationship!
                                Console.WriteLine("GO");
                                Console.WriteLine("ALTER TABLE " + table.ClassName + " WITH NOCHECK");
                                Console.WriteLine("ADD CONSTRAINT FK_" + field.Key + " FOREIGN KEY (" + field.Key + ") REFERENCES " + t2.ClassName + "(ID)");
                                Console.WriteLine("GO");
    
                            }
                        }
                    }
                }
            }
        }
    
        public class TableClass
        {
            private List> _fieldInfo = new List>();
            private string _className = String.Empty;
    
            private Dictionary dataMapper
            {
                get
                {
                    // Add the rest of your CLR Types to SQL Types mapping here
                    Dictionary dataMapper = new Dictionary();
                    dataMapper.Add(typeof(int), "BIGINT");
                    dataMapper.Add(typeof(string), "NVARCHAR(500)");
                    dataMapper.Add(typeof(bool), "BIT");
                    dataMapper.Add(typeof(DateTime), "DATETIME");
                    dataMapper.Add(typeof(float), "FLOAT");
                    dataMapper.Add(typeof(decimal), "DECIMAL(18,0)");
                    dataMapper.Add(typeof(Guid), "UNIQUEIDENTIFIER");
    
                    return dataMapper;
                }
            }
    
            public List> Fields
            {
                get { return this._fieldInfo; }
                set { this._fieldInfo = value; }
            }
    
            public string ClassName
            {
                get { return this._className; }
                set { this._className = value; }
            }
    
            public TableClass(Type t)
            {
                this._className = t.Name;
    
                foreach (PropertyInfo p in t.GetProperties())
                {
                    KeyValuePair field = new KeyValuePair(p.Name, p.PropertyType);
    
                    this.Fields.Add(field);
                }
            }
    
            public string CreateTableScript()
            {
                System.Text.StringBuilder script = new StringBuilder();
    
                script.AppendLine("CREATE TABLE " + this.ClassName);
                script.AppendLine("(");
                script.AppendLine("\t ID BIGINT,");
                for (int i = 0; i < this.Fields.Count; i++)
                {
                    KeyValuePair field = this.Fields[i];
    
                    if (dataMapper.ContainsKey(field.Value))
                    {
                        script.Append("\t " + field.Key + " " + dataMapper[field.Value]);
                    }
                    else
                    {
                        // Complex Type? 
                        script.Append("\t " + field.Key + " BIGINT");
                    }
    
                    if (i != this.Fields.Count - 1)
                    {
                        script.Append(",");
                    }
    
                    script.Append(Environment.NewLine);
                }
    
                script.AppendLine(")");
    
                return script.ToString();
            }
        }
    }
    

    I put these classes in an assembly to test it:

    public class FakeDataClass
    {
        public int AnInt
        {
            get;
            set;
        }
    
        public string AString
        {
            get;
            set;
        }
    
        public float AFloat
        {
            get;
            set;
        }
    
        public FKClass AFKReference
        {
            get;
            set;
        }
    }
    
    public class FKClass
        {
            public int AFKInt
            {
                get;
                set;
            }
        }
    

    And it generated the following SQL:

    CREATE TABLE FakeDataClass
    (
             ID BIGINT,
             AnInt BIGINT,
             AString NVARCHAR(255),
             AFloat FLOAT,
             AFKReference BIGINT
    )
    
    
    CREATE TABLE FKClass
    (
             ID BIGINT,
             AFKInt BIGINT
    )
    
    
    GO
    ALTER TABLE FakeDataClass WITH NOCHECK
    ADD CONSTRAINT FK_AFKReference FOREIGN KEY (AFKReference) REFERENCES FKClass(ID)
    GO
    

    Some further thoughts...I'd consider adding an attribute such as [SqlTable] to your classes, that way it only generates tables for the classes you want. Also, this can be cleaned up a ton, bugs fixed, optimized (the FK Checker is a joke) etc etc...Just to get you started.

提交回复
热议问题