Question

Est-ce quelqu'un connais un moyen de générer automatiquement des tables de base de données pour une classe donnée?Je ne suis pas à la recherche pour l'ensemble d'une couche de persistance - j'ai déjà une solution d'accès aux données que j'utilise, mais j'ai soudain besoin de stocker beaucoup d'informations à partir d'un grand nombre de classes et je ne veux vraiment pas avoir à créer de toutes ces tables à la main.Par exemple, pour la classe suivante:

class Foo
{
    private string property1;
    public string Property1
    {
        get { return property1; }
        set { property1 = value; }
    }

    private int property2;
    public int Property2
    {
        get { return property2; }
        set { property2 = value; }
    }
}

Je m'attends à de la requête SQL suivante:

CREATE TABLE Foo
(
    Property1 VARCHAR(500),
    Property2 INT
)

Je me demande aussi comment vous pourriez poignée de types complexes.Par exemple, dans le précédemment cité de la classe, si nous avons modifié que pour être :

class Foo
{
    private string property1;
    public string Property1
    {
        get { return property1; }
        set { property1 = value; }
    }

    private System.Management.ManagementObject property2;
    public System.Management.ManagementObject Property2
    {
        get { return property2; }
        set { property2 = value; }
    }
}

Comment pourrais-je gérer cela?

J'ai regardé en essayant de s'auto-générer les scripts de base de données par moi-même à l'aide de la réflexion pour énumérer chaque classe de propriétés, mais il est maladroit et les types de données complexes m'ont perplexe.

Était-ce utile?

La solution

C'est vraiment la fin, et je n'ai passé environ 10 minutes sur ce, donc, son extrêmement bâclée, mais il fonctionne et vous donnera un bon point de départ:

using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;

namespace TableGenerator
{
    class Program
    {
        static void Main(string[] args)
        {
            List<TableClass> tables = new List<TableClass>();

            // 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<String, Type> 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<KeyValuePair<String, Type>> _fieldInfo = new List<KeyValuePair<String, Type>>();
        private string _className = String.Empty;

        private Dictionary<Type, String> dataMapper
        {
            get
            {
                // Add the rest of your CLR Types to SQL Types mapping here
                Dictionary<Type, String> dataMapper = new Dictionary<Type, string>();
                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<KeyValuePair<String, Type>> 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<String, Type> field = new KeyValuePair<String, Type>(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<String, Type> 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();
        }
    }
}

J'ai mis ces classes dans une assemblée pour le tester:

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;
        }
    }

Et il a généré la requête SQL suivante:

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

Quelques pensées...je l'avais envisager d'ajouter un attribut tel que [SqlTable] de vos classes, de cette façon, il ne génère que des tables pour les classes que vous souhaitez.Aussi, cela peut être nettoyé jusqu'à une tonne, correction de bugs, optimisation (FK de Checker est une blague) etc etc...Juste pour vous obtenir a commencé.

Autres conseils

@Jonathan Hollande

Wow, je pense que c'est la plus brute travail que j'ai jamais vu mettre un StackOverflow post.Bien fait. Cependant, au lieu de construire des instructions DDL comme des chaînes de caractères, vous devriez certainement utiliser l' SQL Server Management Objects les classes introduites avec SQL 2005.

David Hayden a un post intitulé Créer une Table dans SQL Server 2005 à l'Aide de C# et SQL Server Management Objects (SMO) - la Génération de Code qui marche à travers la façon de créer une table à l'aide de SMO.Les objets fortement typés en font un jeu d'enfant avec des méthodes comme:

// Create new table, called TestTable
Table newTable = new Table(db, "TestTable");

et

// Create a PK Index for the table
Index index = new Index(newTable, "PK_TestTable");
index.IndexKeyType = IndexKeyType.DriPrimaryKey;

VanOrman, si vous utilisez SQL 2005, certainement faire SMO partie de votre solution.

Essayer mon CreateSchema méthode d'extension pour les objets à http://createschema.codeplex.com/

Elle renvoie une chaîne de caractères pour tout objet contenant CRÉER des scripts TABLE.

Je pense que pour les types de données complexes, vous devez étendre le spécifier un ToDB() méthode qui détient leur propre mise en œuvre pour la création des tables dans la base de données, et de cette manière, il devient auto-récursive.

À compter de 2016 (je pense), vous pouvez utiliser Entity Framework 6 le Premier Code pour générer le SQL de schéma de poco classes c# ou utiliser la Première Base de données pour générer du code c# à partir de sql.Le Premier Code de DB procédure pas à pas

Pour les types complexes, vous pouvez récursive convertir chacun que vous rencontrez dans un tableau de son propre, puis à tenter de gérer les relations de clé étrangère.

Vous pouvez également pré-spécifier qui classes ou de ne pas s'être convertis à des tables.Comme pour les complexes de données que vous souhaitez reflète dans la base de données sans les ballonnements le schéma, vous pouvez avoir une ou plusieurs tables pour divers types.Cet exemple utilise 4:

CREATE TABLE MiscTypes /* may have to include standard types as well */
 ( TypeID INT,
   TypeName VARCHAR(...)
 )

CREATE TABLE MiscProperties
 ( PropertyID INT,
   DeclaringTypeID INT, /* FK to MiscTypes */
   PropertyName VARCHAR(...),
   ValueTypeID INT /* FK to MiscTypes */
 )

CREATE TABLE MiscData
 (  ObjectID INT,
    TypeID  INT
 )

CREATE TABLE MiscValues
 ( ObjectID INT, /* FK to MiscData*/
   PropertyID INT,
   Value VARCHAR(...)
 )

Vous pouvez faire l'inverse, table de base de données pour les classes C# ici:http://pureobjects.com/dbCode.aspx

Aussi...peut-être vous pouvez utiliser des outils tels que Visio (pas sûr si Visio fait cela, mais je pense qu'il n') à désosser vos classes en UML et ensuite utiliser UML pour générer la DB Schéma...ou peut-être utiliser un outil tel que ce http://www.tangiblearchitect.net/visual-studio/

Je sais que vous êtes à la recherche pour l'ensemble d'une couche de persistance, mais NHibernate est hbm2ddl tâche peut faire cela presque comme un one-liner.

Il y a un NAnt tâche disponible à l'appeler de ce qui peut être intéressant.

Subsonic est également une autre option.J'ai souvent l'utiliser pour générer les classes d'entité que la carte à une base de données.Il dispose d'un utilitaire de ligne de commande qui vous permet de spécifier les tables, les types, et une foule d'autres choses utiles

Essayez DaoliteMappingTool pour .net.Il peut vous aider à générer les classes.Télécharger le formulaire Ici

Il y a une application gratuite, Schematrix qui génère les classes de DB, de vérifier si l'inverse aussi :) http://www.schematrix.com/products/schemacoder/download.aspx

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top