简体   繁体   English

从XSD生成SQL Server数据库

[英]Generating SQL Server DB from XSD

Duplicate : Generating SQL Schema from XML 重复从XML生成SQL模式


In a project i am working on, i have a need to support either a strongly-typed dataset for storing the data as XML, or storing the data in sql server. 在我正在开发的项目中,我需要支持强类型数据集,用于将数据存储为XML,或者将数据存储在sql server中。 Now i already have the XSD schema created and i would like to be able to create a sql server database using the tables and relationships defined in the XSD. 现在我已经创建了XSD架构,我希望能够使用XSD中定义的表和关系创建一个sql server数据库。

Is this possible? 这可能吗? and if so, what is the best way to approach this problem? 如果是这样,解决这个问题的最佳方法是什么?


Clarification : What i'm looking for is a way to do the above via code at runtime with C# and SQL Server. 澄清 :我正在寻找的是通过C#和SQL Server在运行时通过代码完成上述操作的方法。 Can this be done? 可以这样做吗?

I managed to come up with the following class based on the SQL Server Management Objects: 我设法基于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();
    }

}
}

It hasn't been rigorously tested yet, and there needs to be more SQL to CLR types mapped out, but it does create a new database, all the tables, columns, primary keys, and foreign keys. 它还没有经过严格的测试,并且需要有更多的SQL到CLR类型映射出来,但它确实创建了一个新的数据库,所有的表,列,主键和外键。

For this code to work, a few assemblies need to be referenced: 要使此代码起作用,需要引用一些程序集:

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

Hope this helps someone else out. 希望这有助于其他人。

我会编写一些XSLT来将XSD转换为SQL create语句。

If you are working on SQL2005, you have the possibility to create a table with strongly typed XML columns, so that each value is validated against an XML Schema Collection (ie an XSD). 如果您正在使用SQL2005,则可以创建具有强类型XML列的表,以便针对XML架构集(即XSD)验证每个值。 However I cannot tell you anything about performance, scalability etc. 但是我无法告诉你有关性能,可扩展性等的任何信息。

If you try to translate an XSD into a set of relational tables, you will find that there is no unique mapping between XSD elements and SQL tables: 如果您尝试将XSD转换为一组关系表,您会发现XSD元素和SQL表之间没有唯一的映射:

An XSD child element may be implemented as detail table, as a set of columns representing the element (if only 1 child is allowed), or as mandatory/optional 1:1/1:n relation. XSD子元素可以实现为详细信息表,作为表示元素的一组列(如果仅允许1个子元素),或者作为强制/可选1:1/1:n关系。

A collection of XSD child elements can be a master-detail relation, or an n:m relation stored in a separate table along with the attributes. XSD子元素的集合可以是主 - 细节关系,或者是与属性一起存储在单独的表中的n:m关系。

IIRC there is no definition of primary and unique constraints in XSD, which poses another problem in automated schema generation. IIRC在XSD中没有主要和唯一约束的定义,这在自动化模式生成中提出了另一个问题。

This all does not mean that nobody has yet bothered to develop a tool for such a task. 这一切并不意味着没有人愿意为这样的任务开发工具。 But it certainly means that the task cannot be fully automated. 但它肯定意味着任务无法完全自动化。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM