2009-01-21 118 views
3

重复Generating SQL Schema from XML生成SQL Server数据库从XSD


在一个项目中我的工作,我有必要为支持一个强类型数据集数据存储为XML,或存储在sql server中的数据。现在我已经创建了XSD模式,并且希望能够使用XSD中定义的表和关系创建一个sql server数据库。

这可能吗?如果是的话,解决这个问题的最好方法是什么?


澄清: 我正在寻找一种方法通过代码在C#和SQL Server运行时做以上。这可以做到吗?

+0

Duplicate:http://stackoverflow.com/questions/263836/generating-sql-schema-from-xml – 2009-01-21 22:39:28

+5

不是重复的,因为其他问题指的是oracle和java;这一个涉及SQL Server – devio 2009-01-21 22:56:10

回答

10

我管理的基于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

我会写一些XSLT将XSD转换为SQL创建语句。

0

如果您正在使用SQL2005,则可以使用强类型XML列创建表,以便每个值都针对XML模式集合(即XSD)进行验证。但是我不能告诉你关于性能,可扩展性等什么

如果您尝试翻译的XSD到一组关系表,你会发现,有XSD元素和SQL表之间不存在唯一的对应关系:

一个XSD子元素可以被实现为细节表,作为表示元素的一组列(如果只允许一个孩子),或者作为强制/可选1:1/1:n关系来实现。

XSD子元素的集合可以是一个主 - 关系关系,或一个n:m关系以及属性存储在一个单独的表中。

IIRC XSD中没有主要和唯一约束的定义,这在自动化模式生成中带来了另一个问题。

这并不意味着没有人会为开发此类任务的工具而烦恼。但这当然意味着这项任务不能完全自动化。