C# 클래스에서 데이터베이스 테이블을 생성하려면 어떻게 해야 합니까?

StackOverflow https://stackoverflow.com/questions/47239

  •  09-06-2019
  •  | 
  •  

문제

특정 클래스에 대한 데이터베이스 테이블을 자동 생성하는 방법을 아는 사람이 있습니까?전체 지속성 레이어를 찾고 있는 것이 아닙니다. 이미 사용 중인 데이터 액세스 솔루션이 있지만 갑자기 많은 수의 클래스에서 많은 정보를 저장해야 하고 실제로 생성할 필요가 없습니다. 이 모든 테이블은 손으로.예를 들어 다음 클래스가 있다고 가정해 보겠습니다.

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

나는 다음과 같은 SQL을 기대합니다 :

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

또한 복잡한 유형을 어떻게 처리할 수 있는지 궁금합니다.예를 들어, 이전에 인용한 클래스에서 다음과 같이 변경하면 다음과 같습니다.

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

이 문제를 어떻게 처리할 수 있나요?

각 클래스의 속성을 열거하기 위해 리플렉션을 사용하여 데이터베이스 스크립트를 직접 자동 생성하려고 시도했지만 투박하고 복잡한 데이터 유형으로 인해 어려움을 겪었습니다.

도움이 되었습니까?

해결책

정말 늦었고 이 작업에 10분 정도만 투자했기 때문에 매우 엉성하지만 작동하고 좋은 출발점을 제공할 것입니다.

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

테스트하기 위해 다음 클래스를 어셈블리에 넣었습니다.

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

그리고 다음과 같은 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

몇 가지 추가 생각... [SqlTable]과 같은 속성을 클래스에 추가하는 것이 좋습니다. 이렇게 하면 원하는 클래스에 대한 테이블만 생성됩니다.또한 이것은 엄청난 양의 정리, 버그 수정, 최적화(FK 검사기는 농담입니다) 등이 가능합니다. 시작하기만 하면 됩니다.

다른 팁

@조나단 홀랜드

와, 내 생각엔 StackOverflow 게시물에 담긴 작업 중 가장 원시적인 작업인 것 같아요.잘하셨어요. 하지만, DDL 문을 문자열로 구성하는 대신 반드시 다음을 사용해야 합니다. SQL Server 관리 개체 SQL 2005에 도입된 클래스.

David Hayden이라는 제목의 게시물이 있습니다. C# 및 SMO(SQL Server 관리 개체)를 사용하여 SQL Server 2005에서 테이블 만들기 - 코드 생성 SMO를 사용하여 테이블을 만드는 방법을 안내합니다.강력한 형식의 개체를 사용하면 다음과 같은 메서드를 사용하여 작업을 쉽게 수행할 수 있습니다.

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

그리고

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

VanOrman, SQL 2005를 사용하고 있다면 확실히 SMO를 솔루션의 일부로 만드세요.

다음에서 개체에 대한 CreateSchema 확장 메서드를 사용해 보세요. http://createschema.codeplex.com/

CREATE TABLE 스크립트가 포함된 모든 객체에 대한 문자열을 반환합니다.

복잡한 데이터 유형의 경우 DB에 테이블을 생성하기 위한 자체 구현을 보유하는 ToDB() 메서드를 지정하여 확장해야 하며 이렇게 하면 자동 재귀가 됩니다.

2016년부터는 Entity Framework 6 Code First를 사용하여 poco C# 클래스에서 SQL 스키마를 생성하거나 Database First를 사용하여 SQL에서 C# 코드를 생성할 수 있습니다.Code First에서 DB까지 연습

복합 유형의 경우, 발견한 각 유형을 자체 테이블로 재귀적으로 변환한 다음 외래 키 관계를 관리하려고 시도할 수 있습니다.

미리 지정할 수도 있습니다. 어느 클래스는 테이블로 변환되거나 변환되지 않습니다.스키마를 확장하지 않고 데이터베이스에 반영하려는 복잡한 데이터의 경우 기타 유형에 대해 하나 이상의 테이블을 가질 수 있습니다.이 예에서는 최대 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(...)
 )

여기에서 C# 클래스와 반대되는 데이터베이스 테이블을 수행할 수 있습니다.http://pureobjects.com/dbCode.aspx

또한...아마도 Visio와 같은 도구를 사용하여(Visio가 이 작업을 수행하는지 확실하지 않지만 그럴 것이라고 생각합니다) 클래스를 UML로 리버스 엔지니어링한 다음 UML을 사용하여 DB 스키마를 생성할 수 있습니다.아니면 이와 같은 도구를 사용할 수도 있습니다 http://www.tangiblearchitect.net/visual-studio/

나는 당신이 전체 지속성 레이어를 찾고 있다는 것을 알고 있지만 NHibernate의 hbm2ddl 작업은 이것을 거의 한 줄로 수행할 수 있습니다.

이있다 NAnt 태스크 관심을 가질만한 전화를 걸 수 있습니다.

아음속 또 다른 옵션이기도 합니다.데이터베이스에 매핑되는 엔터티 클래스를 생성하는 데 자주 사용합니다.테이블, 유형 및 기타 유용한 항목을 지정할 수 있는 명령줄 유틸리티가 있습니다.

.net용 DaoliteMappingTool을 사용해 보세요.클래스를 생성하는 데 도움이 될 수 있습니다.양식 다운로드 여기

DB에서 클래스를 생성하는 무료 앱인 Schematrix가 있습니다. 그 반대도 확인해보세요 :) http://www.schematrix.com/products/schemacoder/download.aspx

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top