Генерация БД SQL Server из XSD - PullRequest
3 голосов
/ 22 января 2009

Дубликат : Генерация схемы SQL из XML


В проекте, над которым я работаю, мне необходимо поддерживать либо строго типизированный набор данных для хранения данных в формате XML, либо для хранения данных на сервере sql. Теперь у меня уже есть созданная схема XSD, и я хотел бы иметь возможность создавать базу данных сервера SQL с использованием таблиц и отношений, определенных в XSD.

Возможно ли это? и если да, то как лучше всего подойти к этой проблеме?


Разъяснение : То, что я ищу, это способ сделать это с помощью кода во время выполнения с C # и SQL Server. Можно ли это сделать?

Ответы [ 3 ]

10 голосов
/ 22 января 2009

Мне удалось создать следующий класс на основе объектов управления SQL Server:

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Text;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo;
using Rule=System.Data.Rule;

namespace XSD2SQL
{
public class XSD2SQL
{
    private readonly Server _server;
    private readonly SqlConnection _connection;
    private Database _db;
    private DataSet _source;
    private string _databaseName;

    public XSD2SQL(string connectionString, DataSet source)
    {
        _connection = new SqlConnection(connectionString);
        _server = new Server(new ServerConnection(_connection));
        _source = source;
    }

    public void CreateDatabase(string databaseName)
    {
        _databaseName = databaseName;
        _db = _server.Databases[databaseName];
        if (_db != null) _db.Drop();
        _db = new Database(_server, _databaseName);
        _db.Create();
    }

    public void PopulateDatabase()
    {
        CreateTables(_source.Tables);
        CreateRelationships();
    }

    private void CreateRelationships()
    {
        foreach (DataTable table in _source.Tables)
        {
            foreach (DataRelation rel in table.ChildRelations)
                CreateRelation(rel);
        }
    }

    private void CreateRelation(DataRelation relation)
    {
        Table primaryTable = _db.Tables[relation.ParentTable.TableName];
        Table childTable = _db.Tables[relation.ChildTable.TableName];

        ForeignKey fkey = new ForeignKey(childTable, relation.RelationName);
        fkey.ReferencedTable = primaryTable.Name;

        fkey.DeleteAction = SQLActionTypeToSMO(relation.ChildKeyConstraint.DeleteRule);
        fkey.UpdateAction = SQLActionTypeToSMO(relation.ChildKeyConstraint.UpdateRule);


        for (int i = 0; i < relation.ChildColumns.Length; i++)
        {
            DataColumn col = relation.ChildColumns[i];
            ForeignKeyColumn fkc = new ForeignKeyColumn(fkey, col.ColumnName, relation.ParentColumns[i].ColumnName);

            fkey.Columns.Add(fkc);
        }

        fkey.Create();

    }

    private void CreateTables(DataTableCollection tables)
    {
        foreach (DataTable table in tables)
        {                
            DropExistingTable(table.TableName);
            Table newTable = new Table(_db, table.TableName);

            PopulateTable(ref newTable, table);                
            SetPrimaryKeys(ref newTable, table);
            newTable.Create();

        }
    }

    private void PopulateTable(ref Table outputTable, DataTable inputTable)
    {
        foreach (DataColumn column in inputTable.Columns)
        {
            CreateColumns(ref outputTable, column, inputTable);
        }
    }

    private void CreateColumns(ref Table outputTable, DataColumn inputColumn, DataTable inputTable)
    {
        Column newColumn = new Column(outputTable, inputColumn.ColumnName);
        newColumn.DataType = CLRTypeToSQLType(inputColumn.DataType);
        newColumn.Identity = inputColumn.AutoIncrement;
        newColumn.IdentityIncrement = inputColumn.AutoIncrementStep;
        newColumn.IdentitySeed = inputColumn.AutoIncrementSeed;
        newColumn.Nullable = inputColumn.AllowDBNull;
        newColumn.UserData = inputColumn.DefaultValue;

        outputTable.Columns.Add(newColumn);
    }

    private void SetPrimaryKeys(ref Table outputTable, DataTable inputTable)
    {
        Index newIndex = new Index(outputTable, "PK_" + outputTable.Name);
        newIndex.IndexKeyType = IndexKeyType.DriPrimaryKey;
        newIndex.IsClustered = false;

        foreach (DataColumn keyColumn in inputTable.PrimaryKey)
        {                                
            newIndex.IndexedColumns.Add(new IndexedColumn(newIndex, keyColumn.ColumnName, true));                
        }
        if (newIndex.IndexedColumns.Count > 0)
            outputTable.Indexes.Add(newIndex);
    }



    private DataType CLRTypeToSQLType(Type type)
    {
        switch (type.Name)
        {
            case "String":
                return DataType.NVarCharMax;

            case "Int32":
                return DataType.Int;

            case "Boolean":
                return DataType.Bit;

            case "DateTime":
                return DataType.DateTime;

            case "Byte[]":
                return DataType.VarBinaryMax;


        }

        return DataType.NVarCharMax;
    }

    private ForeignKeyAction SQLActionTypeToSMO(Rule rule)
    {
        string ruleStr = rule.ToString();

        return (ForeignKeyAction)Enum.Parse(typeof (ForeignKeyAction), ruleStr);
    }

    private void DropExistingTable(string tableName)
    {
        Table table = _db.Tables[tableName];
        if (table != null) table.Drop();
    }

}
}

Он еще не был тщательно протестирован, и необходимо сопоставить больше типов SQL и CLR, но он создает новую базу данных, все таблицы, столбцы, первичные ключи и внешние ключи.

Чтобы этот код работал, нужно сослаться на несколько сборок:

Microsoft.SqlServer.ConnectionInfo
Microsoft.SqlServer.Management.Sdk.Sfc
Microsoft.SqlServer.Smo
Microsoft.SqlServer.SqlEnum

Надеюсь, это поможет кому-то еще.

1 голос
/ 22 января 2009

Я бы написал несколько XSLT, чтобы превратить XSD в операторы SQL create.

0 голосов
/ 22 января 2009

Если вы работаете с SQL2005, у вас есть возможность создать таблицу со строго типизированными столбцами XML, чтобы каждое значение проверялось в соответствии с коллекцией схем XML (то есть XSD). Однако я ничего не могу вам сказать о производительности, масштабируемости и т. Д.

Если вы попытаетесь преобразовать XSD в набор реляционных таблиц, вы обнаружите, что не существует уникального отображения между элементами XSD и таблицами SQL:

Дочерний элемент XSD может быть реализован как подробная таблица, как набор столбцов, представляющих элемент (если разрешен только 1 дочерний элемент), или как обязательное / необязательное отношение 1: 1/1: n.

Набор дочерних элементов XSD может представлять собой отношение master-detail или отношение n: m, хранящееся в отдельной таблице вместе с атрибутами.

В IIRC отсутствует определение первичных и уникальных ограничений в XSD, что создает другую проблему при автоматической генерации схемы.

Все это не означает, что еще никто не удосужился разработать инструмент для такой задачи. Но это, безусловно, означает, что задача не может быть полностью автоматизирована.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...