J'ai réussi à créer la classe suivante basée sur les objets de gestion de serveur SQL :
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 _connexion;
private Database _db;
private DataSet _source;
private string _nomBaseDeDonnees;
public XSD2SQL(string chaineConnexion, DataSet source)
{
_connexion = new SqlConnection(chaineConnexion);
_server = new Server(new ServerConnection(_connexion));
_source = source;
}
public void CreerBaseDeDonnees(string nomBaseDeDonnees)
{
_nomBaseDeDonnees = nomBaseDeDonnees;
_db = _server.Databases[nomBaseDeDonnees];
if (_db != null) _db.Drop();
_db = new Database(_server, _nomBaseDeDonnees);
_db.Create();
}
public void PeuplerBaseDeDonnees()
{
CreerTables(_source.Tables);
CreerRelations();
}
private void CreerRelations()
{
foreach (DataTable table in _source.Tables)
{
foreach (DataRelation rel in table.ChildRelations)
CreerRelation(rel);
}
}
private void CreerRelation(DataRelation relation)
{
Table tablePrincipale = _db.Tables[relation.ParentTable.TableName];
Table tableEnfant = _db.Tables[relation.ChildTable.TableName];
ForeignKey cleEtrangere = new ForeignKey(tableEnfant, relation.RelationName);
cleEtrangere.ReferencedTable = tablePrincipale.Name;
cleEtrangere.DeleteAction = SQLActionTypeToSMO(relation.ChildKeyConstraint.DeleteRule);
cleEtrangere.UpdateAction = SQLActionTypeToSMO(relation.ChildKeyConstraint.UpdateRule);
for (int i = 0; i < relation.ChildColumns.Length; i++)
{
DataColumn colonne = relation.ChildColumns[i];
ForeignKeyColumn fkc = new ForeignKeyColumn(cleEtrangere, colonne.ColumnName, relation.ParentColumns[i].ColumnName);
cleEtrangere.Columns.Add(fkc);
}
cleEtrangere.Create();
}
private void CreerTables(DataTableCollection tables)
{
foreach (DataTable table in tables)
{
SupprimerTableExistante(table.TableName);
Table nouvelleTable = new Table(_db, table.TableName);
PeuplerTable(ref nouvelleTable, table);
DefinirClesPrimaires(ref nouvelleTable, table);
nouvelleTable.Create();
}
}
private void PeuplerTable(ref Table tableSortie, DataTable tableEntree)
{
foreach (DataColumn colonne in tableEntree.Columns)
{
CreerColonnes(ref tableSortie, colonne, tableEntree);
}
}
private void CreerColonnes(ref Table tableSortie, DataColumn colonneEntree, DataTable tableEntree)
{
Column nouvelleColonne = new Column(tableSortie, colonneEntree.ColumnName);
nouvelleColonne.DataType = CLRTypeToSQLType(colonneEntree.DataType);
nouvelleColonne.Identity = colonneEntree.AutoIncrement;
nouvelleColonne.IdentityIncrement = colonneEntree.AutoIncrementStep;
nouvelleColonne.IdentitySeed = colonneEntree.AutoIncrementSeed;
nouvelleColonne.Nullable = colonneEntree.AllowDBNull;
nouvelleColonne.UserData = colonneEntree.DefaultValue;
tableSortie.Columns.Add(nouvelleColonne);
}
private void DefinirClesPrimaires(ref Table tableSortie, DataTable tableEntree)
{
Index nouvelIndex = new Index(tableSortie, "PK_" + tableSortie.Name);
nouvelIndex.IndexKeyType = IndexKeyType.DriPrimaryKey;
nouvelIndex.IsClustered = false;
foreach (DataColumn colonneCle in tableEntree.PrimaryKey)
{
nouvelIndex.IndexedColumns.Add(new IndexedColumn(nouvelIndex, colonneCle.ColumnName, true));
}
if (nouvelIndex.IndexedColumns.Count > 0)
tableSortie.Indexes.Add(nouvelIndex);
}
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 SupprimerTableExistante(string nomTable)
{
Table table = _db.Tables[nomTable];
if (table != null) table.Drop();
}
}
}
Il n'a pas encore été rigoureusement testé, et il doit y avoir plus de types SQL à CLR à mapper, mais il crée une nouvelle base de données, toutes les tables, colonnes, clés primaires et clés étrangères.
Pour que ce code fonctionne, quelques assemblies doivent être référencées :
Microsoft.SqlServer.ConnectionInfo
Microsoft.SqlServer.Management.Sdk.Sfc
Microsoft.SqlServer.Smo
Microsoft.SqlServer.SqlEnum
En espérant que cela aidera quelqu'un d'autre.