DataTable 到带有实体框架的 SQL Server 表

Posted

技术标签:

【中文标题】DataTable 到带有实体框架的 SQL Server 表【英文标题】:DataTable to SQL Server tables with Entity Framework 【发布时间】:2019-01-31 01:10:53 【问题描述】:

我有一个数据集,其中包含多个表和关系。我希望能够使用实体框架将我的数据集表转换为 SQL 服务器表集。我看到了填写表格的文章 - 但实际上我将如何处理一些这样的伪代码。

for each dataTable in ds.Tables

    Create a table in SQL Server with these columns

创建后我想添加关系..然后填充数据。

我通过读取 xml 文件在数据集中获取这些表,我有由 xsd.exe 创建的类

【问题讨论】:

哇,这可能是一个项目。不仅仅是一个问题。最新的 EF 支持代码优先,这意味着您必须首先对模式进行硬编码。但是你也可以使用 Scaffold-Context 来反转数据库,但是你必须先对数据库进行硬编码。 所以你想要一个 API 来为 SQL Server 创建数据库对象,我说对了吗? EF 可用于插入该数据,但如果您想从该方法创建 db 结构,则需要 SMO 但是仍然可以创建表,但您不必使用 EF,因为 ADO.NET 足以完成这项工作。 @moro91 是的,我正在导入 XML 文件,我想做一个简单的事情,比如 EF.Table.Create,但我想旧的硬方法是唯一的方法。 @Dongdong 我的模式位于从 xml / 通过我使用 xsd.exe 生成的类翻译文件导入的数据集和数据表中。我还有一个用于验证 xml 的 xsd 文件。 【参考方案1】:

我不能说我完全按照提出的方式回答了这个问题——因为似乎没有实体框架可以解决这个问题。但是,我发布此答案的主要目的是,以防其他人正在寻找代码来翻译数据集、其表和关系,然后在 SQLServer 中创建它们。下面的代码使用 SQLClient 的标准 .NET 库。没有使用 SMO。

大部分代码不是我的,而是来自用户:010110110101,Converting a DataTable to an CREATE TABLE + INSERT script for SQL in C#

我对代码的主要贡献是修复了代码中的一些小错误,并添加了 Alter Table sql 以及生成关系的方法。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Data;

namespace Helpers.Sql


    public class TableCreator
    
        #region Instance Variables
        private SqlConnection _connection;
        public SqlConnection Connection
        
            get  return _connection; 
            set  _connection = value; 
        

        private SqlTransaction _transaction;
        public SqlTransaction Transaction
        
            get  return _transaction; 
            set  _transaction = value; 
        

        private string _tableName;
        public string DestinationTableName
        
            get  return _tableName; 
            set  _tableName = value; 
        
        #endregion

        #region Constructor
        public TableCreator()  
        public TableCreator(SqlConnection connection) : this(connection, null)  
        public TableCreator(SqlConnection connection, SqlTransaction transaction)
        
            _connection = connection;
            _transaction = transaction;
        

        public TableCreator(string connectionString)
        

            this.Connection = new SqlConnection(connectionString);

        


        #endregion

        #region Instance Methods
        public object Create(DataTable schema)
        
            return Create(schema, null);
        
        public object Create(DataTable schema, int numKeys)
        
            int[] primaryKeys = new int[numKeys];
            for (int i = 0; i < numKeys; i++)
            
                primaryKeys[i] = i;
            
            return Create(schema, primaryKeys);
        
        public object Create(DataTable schema, int[] primaryKeys)
        
            string sql = GetCreateSQL(_tableName, schema, primaryKeys);

            SqlCommand cmd;
            if (_transaction != null && _transaction.Connection != null)
                cmd = new SqlCommand(sql, _connection, _transaction);
            else
                cmd = new SqlCommand(sql, _connection);

            return cmd.ExecuteNonQuery();
        

        public object CreateFromDataTable(DataTable table)
        
            DestinationTableName = table.TableName;

            string sql = GetCreateFromDataTableSQL(_tableName, table);

            SqlCommand cmd;
            if (_transaction != null && _transaction.Connection != null)
                cmd = new SqlCommand(sql, _connection, _transaction);
            else
                cmd = new SqlCommand(sql, _connection);

            return cmd.ExecuteNonQuery();
        


        /// <summary>
        /// Creates a Data Relation
        /// </summary>
        /// <param name="_relation"></param>
        /// <returns></returns>
        public object CreateRelationFromDataSet(DataRelation _relation)
        

            string sql = GetCreateFromDatSetRelations(_relation);

            SqlCommand cmd;
            if (_transaction != null && _transaction.Connection != null)
                cmd = new SqlCommand(sql, _connection, _transaction);
            else
                cmd = new SqlCommand(sql, _connection);

            return cmd.ExecuteNonQuery();

        


        #endregion

        #region Static Methods

        /// <summary>
        /// 
        /// </summary>
        /// <param name="tableName"></param>
        /// <param name="schema"></param>
        /// <param name="primaryKeys"></param>
        /// <returns></returns>
        public static string GetCreateSQL(string tableName, DataTable schema, int[] primaryKeys)
        
            string sql = "CREATE TABLE [" + tableName + "] (\n";

            // columns
            foreach (DataRow column in schema.Rows)
            
                if (!(schema.Columns.Contains("IsHidden") && (bool)column["IsHidden"]))
                
                    sql += "\t[" + column["ColumnName"].ToString() + "] " + SQLGetType(column);

                    if (schema.Columns.Contains("AllowDBNull") && (bool)column["AllowDBNull"] == false)
                        sql += " NOT NULL";

                    sql += ",\n";
                
            
            sql = sql.TrimEnd(new char[]  ',', '\n' ) + "\n";

            // primary keys
            string pk = ", CONSTRAINT PK_" + tableName + " PRIMARY KEY CLUSTERED (";
            bool hasKeys = (primaryKeys != null && primaryKeys.Length > 0);
            if (hasKeys)
            
                // user defined keys
                foreach (int key in primaryKeys)
                
                    pk += schema.Rows[key]["ColumnName"].ToString() + ", ";
                
            
            else
            
                // check schema for keys
                string keys = string.Join(", ", GetPrimaryKeys(schema));
                pk += keys;
                hasKeys = keys.Length > 0;
            
            pk = pk.TrimEnd(new char[]  ',', ' ', '\n' ) + ")\n";
            if (hasKeys) sql += pk;

            sql += ")";

            return sql;
        

        /// <summary>
        /// 
        /// </summary>
        /// <param name="tableName"></param>
        /// <param name="table"></param>
        /// <returns></returns>
        public static string GetCreateFromDataTableSQL(string tableName, DataTable table)
        
            string sql = "CREATE TABLE [" + tableName + "] (\n";
            // columns
            foreach (DataColumn column in table.Columns)
            
                sql += "[" + column.ColumnName + "] " + SQLGetType(column) + ",\n";
            
            sql = sql.TrimEnd(new char[]  ',', '\n' ) + "\n";
            // primary keys
            if (table.PrimaryKey.Length > 0)
            
                sql += "CONSTRAINT [PK_" + tableName + "] PRIMARY KEY CLUSTERED (";
                foreach (DataColumn column in table.PrimaryKey)
                
                    sql += "[" + column.ColumnName + "],";
                
                sql = sql.TrimEnd(new char[]  ',' ) + "))\n";
            

            //if not ends with ")"
            if ((table.PrimaryKey.Length == 0) && (!sql.EndsWith(")")))
            
                sql += ")";
            

            return sql;
        

        /// <summary>
        /// 
        /// </summary>
        /// <param name="relation"></param>
        /// <returns></returns>
        public static string GetCreateFromDatSetRelations(DataRelation relation)
        

            // string sql = "";

            string childTableName = relation.ChildTable.TableName;
            string parentTableName = relation.ParentTable.TableName;

            string sql = "ALTER TABLE [" + childTableName + "] ADD CONSTRAINT \n";

            //sql += "ADD CONSTRAINT \n";

            // Add the relation - if the name is in the dataset use it.
            if (string.IsNullOrEmpty(relation.RelationName))
            
                sql += "FK_" + childTableName + "_" + parentTableName;
            
            else
            
                sql += relation.RelationName;
            

            sql += " FOREIGN KEY \n(\n";

            // Set up the keys for the Columns that have foreign 

            for (int i = 0; i < relation.ChildKeyConstraint.Columns.Length; i++)
            

                sql += relation.ChildKeyConstraint.Columns[i].ColumnName;

                if ((relation.ChildKeyConstraint.Columns.Length > 1 ) & i < (relation.ChildKeyConstraint.Columns.Length - 1))
                
                    sql += ",";
                

                sql += "\n";

            


            // Set up the reference columns.

            sql += "\n) REFERENCES " + parentTableName + "\n(\n";

            //   int cols = relation.ParentKeyConstraint.Columns.Length;

            for (int i = 0; i < relation.ParentKeyConstraint.Columns.Length; i++)
            

                sql += relation.ParentKeyConstraint.Columns[i].ColumnName;

                if ((relation.ParentKeyConstraint.Columns.Length > 1) & i < (relation.ParentKeyConstraint.Columns.Length - 1))
                
                    sql += ",";
                

                sql += "\n";

            

            sql += ") \n ON UPDATE NO ACTION  \n ON DELETE NO ACTION";


            return sql;
        




        /// <summary>
        /// 
        /// </summary>
        /// <param name="schema"></param>
        /// <returns></returns>
        public static string[] GetPrimaryKeys(DataTable schema)
        
            List<string> keys = new List<string>();

            foreach (DataRow column in schema.Rows)
            
                if (schema.Columns.Contains("IsKey") && (bool)column["IsKey"])
                    keys.Add(column["ColumnName"].ToString());
            

            return keys.ToArray();
        

        // Return T-SQL data type definition, based on schema definition for a column
        public static string SQLGetType(object type, int columnSize, int numericPrecision, int numericScale)
        
            switch (type.ToString())
            
                case "System.String":
                    return "VARCHAR(" + ((columnSize == -1) ? "255" : (columnSize > 8000) ? "MAX" : columnSize.ToString()) + ")";

                case "System.Decimal":
                    if (numericScale > 0)
                        return "REAL";
                    else if (numericPrecision > 10)
                        return "BIGINT";
                    else
                        return "INT";

                case "System.Double":
                case "System.Single":
                    return "REAL";

                case "System.Int64":
                    return "BIGINT";

                case "System.Int16":
                case "System.Int32":
                    return "INT";

                case "System.DateTime":
                    return "DATETIME";

                case "System.Boolean":
                    return "BIT";

                case "System.Byte":
                    return "TINYINT";

                case "System.Guid":
                    return "UNIQUEIDENTIFIER";

                default:
                    throw new Exception(type.ToString() + " not implemented.");
            
        

        // Overload based on row from schema table
        public static string SQLGetType(DataRow schemaRow)
        
            return SQLGetType(schemaRow["DataType"],
                                int.Parse(schemaRow["ColumnSize"].ToString()),
                                int.Parse(schemaRow["NumericPrecision"].ToString()),
                                int.Parse(schemaRow["NumericScale"].ToString()));
        
        // Overload based on DataColumn from DataTable type
        public static string SQLGetType(DataColumn column)
        
            return SQLGetType(column.DataType, column.MaxLength, 10, 2);
        
        #endregion

        /// <summary>
        /// 
        /// </summary>
        /// <param name="connectionString"></param>
        /// <param name="tableName"></param>
        /// <param name="table"></param>
        public static void BulkInsertDataTable(string connectionString, string tableName, DataTable table)
        
            using (SqlConnection connection = new SqlConnection(connectionString))
            
                SqlBulkCopy bulkCopy =
                    new SqlBulkCopy
                    (
                    connection,
                    SqlBulkCopyOptions.TableLock |
                    SqlBulkCopyOptions.FireTriggers |
                    SqlBulkCopyOptions.UseInternalTransaction,
                    null
                    );

                bulkCopy.DestinationTableName = tableName;
                connection.Open();

                bulkCopy.WriteToServer(table);
                connection.Close();
            
        
    


    /// <summary>
    /// 
    /// </summary>
    public class CreateServerModel
    

        public void CreateServerTables(DataSet ds, SqlConnection conn)
        

            TableCreator STC = new TableCreator(conn);

            STC.Connection.Open();
            foreach (DataTable dt in ds.Tables)
            

                STC.CreateFromDataTable(dt);

            
            STC.Connection.Close();
        

        /// <summary>
        /// 
        /// </summary>
        /// <param name="ds"></param>
        /// <param name="conn"></param>
        public void CreateTableRelations(DataSet ds, SqlConnection conn)
        

            TableCreator STC = new TableCreator(conn);

            STC.Connection.Open();

            foreach (DataRelation relation in ds.Relations)
            
                //STC.Get
                //string chTblName = item.ChildTable.TableName;
                //string prntTblName = item.ParentTable.TableName;


                //List<DataColumn> lchColumns = relation.ChildKeyConstraint.Columns.ToList();
                //List<DataColumn> parColumns = relation.ParentKeyConstraint.Columns.ToList();
                //string prntTblName = relation.ParentTable.TableName;
                try
                
                    STC.CreateRelationFromDataSet(relation);
                
                catch (Exception ex)
                
                    string msg = ex.Message.ToString();
                    // throw;
                    msg += "";
                


            

            STC.Connection.Close();
        

    

【讨论】:

以上是关于DataTable 到带有实体框架的 SQL Server 表的主要内容,如果未能解决你的问题,请参考以下文章

带有 Firebird 的实体框架引发动态 SQL 错误

使用带有 SqlCommandBuilder 的 TableAdapter 和导出到 DataTable 的工作表来更新 SQL 数据库表

带有存储过程的实体框架 VS LINQ to SQL VS ADO.NET? [关闭]

在Code第一实体框架中将DbContext转换为Datatable

使用带有 MVC4 SQL Server 的实体框架插入后触发器不会触发

在带有 Linq 的实体框架中使用 LIKE "%%%"? [复制]