【问题标题】:Export SQL DataBase to WinForm DataSet and then to MDB Database using DataSet将 SQL 数据库导出到 WinForm 数据集,然后使用数据集导出到 MDB 数据库
【发布时间】:2012-05-28 14:41:57
【问题描述】:

我的应用程序是一个依赖数据库的 winform 应用程序。在应用程序启动时,它连接到服务器上的 SQL 数据库,并将此信息放入 DataSet/DataTable 中。

如果由于某种原因无法访问服务器上的数据库,则应用程序具有内置的故障转移功能,它将从本地数据库中获取信息。

如果在正常情况下,我启动将从 sql 数据库读取的工具,并且如果它已在服务器上更新(单独的 sn-p 检查),它应该确保本地数据库最多日期,这就是问题开始的地方..(见下文)

这部分工作正常并作为上下文添加 - 这是我们连接到 SQL 数据库的地方

    public static DataSet dtsTableContents;
    public static DataTable CreateDatabaseSQLConnection()
    {
        try
        {
            string strSqlConnectionString = "Data Source=MyLocation;Initial Catalog=MyCatalog;User=MyUser;Password=MyPassword;";
            SqlCommand scoCommand = new SqlCommand();
            scoCommand.Connection = new SqlConnection(strSqlConnectionString);
            scoCommand.Connection.Open();
            string strQueryToTable = "SELECT * FROM " + strTableName;
            dtsTableContents = new DataSet();
            SqlCommand scmTableInformation = new SqlCommand(strQueryToTable, scnConnectionToDatabase);
            SqlDataAdapter sdaTableInformation = new SqlDataAdapter(scmTableInformation);
            scnConnectionToDatabase.Open();
            sdaTableInformation.Fill(dtsTableContents, strTableName);
            DataTable dttTableInformation = dtsTableContents.Tables[strTableName];
            scnConnectionToDatabase.Close();
            return dttTableInformation;
        }
        catch
        {
            return null;
        }
    }

这个 sn-p 是从我的本地数据库读取的故障转移方法的一部分...

这部分工作正常并作为上下文添加 - 这是我们连接到 MDB 数据库的地方

public static DataTable CreateDatabaseConnection()
    {
        try
        {
            string ConnectionString = @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=MyLocation;Persist Security Info=True;JET OLEDB:Database Password=MyPassword;"
            odcConnection = new OleDbConnection(ConnectionString);
            odcConnection.Open();
            string strQueryToTable = "SELECT * FROM " + strTableName;
            DataSet dtsTableContents = new DataSet();
            OleDbCommand ocmTableInformation = new OleDbCommand(strQueryToTable, ocnConnectionToDatabase);
            OleDbDataAdapter odaTableInformation = new OleDbDataAdapter(ocmTableInformation);
            ocnConnectionToDatabase.Open();
            odaTableInformation.Fill(dtsTableContents, strTableName);
            DataTable dttTableInformation = dtsTableContents.Tables[strTableName];
            ocnConnectionToDatabase.Close();
            return dttTableInformation;
        }
        catch
        {
            return null;
        }
    }

从我的 CreateDatabaseSQLConnection() 我有一个数据集。验证此 DataSet 包含来自服务器数据库的所有信息。现在我一直在谷歌搜索,发现自己试图根据这篇文章使用这段代码来更新本地数据库: http://msdn.microsoft.com/en-us/library/system.data.common.dataadapter.update(v=vs.71).aspx

public static void UpdateLocalDatabase(string strTableName)
    {
        try
        {
            if (CreateDatabaseConnection() != null)
            {
                string strQueryToTable = "SELECT * FROM " + strTableName;
                OleDbDataAdapter odaTableInformation = new OleDbDataAdapter();
                odaTableInformation.SelectCommand = new OleDbCommand(strQueryToTable, odcConnection);
                OleDbCommandBuilder ocbCommand = new OleDbCommandBuilder(odaTableInformation);
                odcConnection.Open();
                odaTableInformation.Update(dtsTableContents, strTableName);
                odcConnection.Close();
            }
        }
        catch { }
    }

这个 sn-p 运行没有错误,但它似乎没有改变任何东西。运行此步骤所需的时间也需要几毫秒,我认为这需要更长的时间。

我正在使用从我的 SQL 连接获得的数据集,我正在尝试将这个数据集写入我的本地数据库。

这可能是因为这是来自 SQL 连接的 DataSet,我无法通过 OleDbAdapter 将其写入我的 mdb 连接,还是我只是在这里遗漏了明显的东西?

感谢任何帮助。

谢谢,

凯文

【问题讨论】:

    标签: c# sql winforms oledb


    【解决方案1】:

    从外部数据库直接备份到内部备份

    我刚刚搞砸了一个 sdf 和一个基于服务器的 sql 数据库,它已经工作了。这绝不是成品,但对于一列,我有程序可以从外部数据库中读取,并且然后用大约 15 行代码直接写入本地 .sdf

                SqlConnection sqlCon = new SqlConnection( ExternalDatabaseConnectionString );
                SqlCeConnection sqlCECon = new SqlCeConnection( BackUpConnectionString );
                using ( sqlCon )
                    {
                    using ( sqlCECon )
    
                        {
                        sqlCon.Open( );
                        sqlCECon.Open( );
                        SqlCommand get = new SqlCommand( "Select * from [TableToRead]", sqlCon );
                        SqlCeCommand save = new SqlCeCommand( "Update [BackUpTable] set InfoColumn = @info where ID = @id", sqlCECon );
                        SqlDataReader reader = get.ExecuteReader( );
                        if ( reader.HasRows )
                            {
                            reader.Read( );
    save.Parameters.AddWithValue("@id", reader.GetString(0));
                                save.Parameters.AddWithValue( "@info", reader.GetString( 1 ));
                                save.ExecuteNonQuery( );
                                }
                            }
                        }
    

    对于数据库的一行,备份一列,它可以工作,我假设你会有某种自动递增的键,比如 ID?

    【讨论】:

    • 嗨,Alex,哇,如果你“破解”它,这将是多么酷。我正在使用一个包含 3 个表的数据库,并且它们都有一个自动递增的 ID 列。如果我实现了这个,我假设我可以通过为我的每个表循环来让它工作?谢谢
    【解决方案2】:

    我认为第一步是减少您对static 方法和字段的依赖。

    如果您查看您的 UpdateLocalDatabase 方法,您会发现您正在传递该方法使用的 strTableName,但 UpdateLocalDatabase 调用的方法 (CreateDatabaseConnection) 引用了不同的全局静态变量同名。很可能这两个 strTableName 变量包含不同的值,而您看不到它们不是同一个变量。

    您还试图在UpdateLocalDatabase 中写出全局静态数据集dtsTableContents,但是如果您再查看CreateDatabaseConnection,它实际上会创建该变量的本地版本——同样,您有两个名为一个是全局的,一个是本地的。

    我怀疑dtsTableContents的两个变量是问题。

    再次,我的建议是不要使用任何静态方法或变量,并且对于您在这里所做的事情,尽量不要使用任何全局变量。此外,重构和/或重命名您的方法以匹配更多他们实际在做的事情。

    【讨论】:

    • 嗨,布拉德,感谢您的回答。我会尝试使用更少的(全局)静态变量。我使用它们的原因是因为这些代码 sn-ps 位于单独的 DLL 中,并且由主可执行文件触发。我可以肯定地说它与 dtsTableContents 无关,因为它是在触发此方法之前分配的,但我将这部分排除在外,因为我的问题已经太长了。如果不设置全局静态变量以与我的 dll 和 exe 快速交互,最好的方法是什么?我假设的另一个选择是每次都创建一个单独的实例? - 谢谢
    • @Xikiryox,我建议单步调试调试器中的代码。由于这是一个单独的 DLL,如果它在不同的进程中,您可能需要调试 |附加进程以对其进行调试。我不相信全部静态化会有那么有益,特别是因为你给出的代码看起来有很大的空间让事情发生意外。我将首先将其更改为非静态并且不使用尽可能多的全局变量,因为我相信这将阐明当前的一些问题。一旦它以这种方式工作,如果您需要性能,请考虑静态。
    • 作为一个想法:您是否尝试检查互联网连接可用性,然后尝试连接到服务器?以及为什么不将数据集完全写入 PC 上的一些 XML 文档并将其保存在应用程序路径中?
    • @sihirbazzz 原因是因为数据库已加密,并非所有数据都应该可见,因此我无法将信息放入 XML 文件中。所以我有点卡住了,因为我必须使用 sdf/mdb/accdb 文件 - 谢谢。
    【解决方案3】:

    在无休止地尝试使用 DataAdapter.Update(Method) 之后,我放弃了。我决定使用 sdf 文件而不是 mdb。

    如果我需要更新我的数据库,我删除本地数据库,创建一个新的,使用相同的连接字符串。然后我遍历我的数据集中的表,从中读取列名和类型,并以此为基础创建表。

    在此之后,我遍历我的数据集并插入我用来自服务器的信息填充的数据集的内容。下面是代码,这只是“快速而肮脏”的概念证明,但它适用于我的场景。

    public static void RemoveAndCreateLocalDb(string strLocalDbLocation)
        {
            try
            {
                if (File.Exists(strLocalDbLocation))
                {
                    File.Delete(strLocalDbLocation);
                }
                SqlCeEngine sceEngine = new SqlCeEngine(@"Data Source= " + strLocalDbLocation + ";Persist Security Info=True;Password=MyPass");
                sceEngine.CreateDatabase();
            }
            catch
            { }
        }
    
    public static void UpdateLocalDatabase(String strTableName, DataTable dttTable)
        {
            try
            {
    
                // Opening the Connection
                sceConnection = CreateDatabaseSQLCEConnection();
                sceConnection.Open();
    
                // Creating tables in sdf file - checking headers and types and adding them to a query
                StringBuilder stbSqlGetHeaders = new StringBuilder();
                stbSqlGetHeaders.Append("create table " + strTableName + " (");
                int z = 0;
                foreach (DataColumn col in dttTable.Columns)
                {
                    if (z != 0) stbSqlGetHeaders.Append(", "); ;
                    String strName = col.ColumnName;
                    String strType = col.DataType.ToString();
                    if (strType.Equals("")) throw new ArgumentException("DataType Empty");
                    if (strType.Equals("System.Int32")) strType = "int";
                    if (strType.Equals("System.String")) strType = "nvarchar (100)";
                    if (strType.Equals("System.Boolean")) strType = "nvarchar (15)";
                    if (strType.Equals("System.DateTime")) strType = "datetime";
                    if (strType.Equals("System.Byte[]")) strType = "nvarchar (100)";
    
                    stbSqlGetHeaders.Append(strName + " " + strType);
                    z++;
                }
                stbSqlGetHeaders.Append(" )");
                SqlCeCommand sceCreateTableCommand;
                string strCreateTableQuery = stbSqlGetHeaders.ToString();
                sceCreateTableCommand = new SqlCeCommand(strCreateTableQuery, sceConnection);
    
                sceCreateTableCommand.ExecuteNonQuery();
    
    
                StringBuilder stbSqlQuery = new StringBuilder();
                StringBuilder stbFields = new StringBuilder();
                StringBuilder stbParameters = new StringBuilder();
    
                stbSqlQuery.Append("insert into " + strTableName + " (");
    
                foreach (DataColumn col in dttTable.Columns)
                {
                    stbFields.Append(col.ColumnName);
                    stbParameters.Append("@" + col.ColumnName.ToLower());
                    if (col.ColumnName != dttTable.Columns[dttTable.Columns.Count - 1].ColumnName)
                    {
                        stbFields.Append(", ");
                        stbParameters.Append(", ");
                    }
                }
                stbSqlQuery.Append(stbFields.ToString() + ") ");
                stbSqlQuery.Append("values (");
                stbSqlQuery.Append(stbParameters.ToString() + ") ");
    
                string strTotalRows = dttTable.Rows.Count.ToString();
    
                foreach (DataRow row in dttTable.Rows)
                {
                    SqlCeCommand sceInsertCommand = new SqlCeCommand(stbSqlQuery.ToString(), sceConnection);
                    foreach (DataColumn col in dttTable.Columns)
                    {
                        if (col.ColumnName.ToLower() == "ssma_timestamp")
                        {
                            sceInsertCommand.Parameters.AddWithValue("@" + col.ColumnName.ToLower(), "");
                        }
                        else
                        {
                            sceInsertCommand.Parameters.AddWithValue("@" + col.ColumnName.ToLower(), row[col.ColumnName]);
                        }
                    }
                    sceInsertCommand.ExecuteNonQuery();
                }
            }
            catch { }
        }
    

    【讨论】:

    • 这是在黑暗中的狂野刺伤,但你能不能打开两个连接,创建 2 个命令,一个从外部数据库读取,一个写入内部数据库,然后从那里说 updateLocalBackUpcmd.paramaters .addwithvalue("@Paramater", reader.readline(1)) 我不知道这是否可能,但可以阻止您使用本地数据集吗?您还可以通过使用 UPDATE 命令而不是删除和重新填充数据库来节省时间
    猜你喜欢
    • 2011-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-15
    • 1970-01-01
    相关资源
    最近更新 更多