【问题标题】:Reading/Writing DataTables to and from an OleDb Database LINQ从 OleDb 数据库 LINQ 读取/写入数据表
【发布时间】:2010-04-16 21:54:27
【问题描述】:

我目前的项目是从OleDbDatabase 和 .CSV 文件中获取信息,并将其全部放入更大的OleDbDatabase

我目前已经从两个 .CSV 文件中读取了我需要的所有信息,并将 OleDbDatabase 读入 DataTables.... 问题在于将所有信息写回另一个 OleDbDatabase。

现在我目前的方法是做这样的事情:

    OleDbTransaction myTransaction = null;

    try
    {
        OleDbConnection conn = new OleDbConnection("PROVIDER=Microsoft.Jet.OLEDB.4.0;" +
                                                   "Data Source=" + Database);
        conn.Open();
        OleDbCommand command = conn.CreateCommand();
        string strSQL;

        command.Transaction = myTransaction;

        strSQL = "Insert into TABLE " +
                 "(FirstName, LastName) values ('" +
                 FirstName + "', '" + LastName + "')";

        command.CommandType = CommandType.Text;
        command.CommandText = strSQL;

        command.ExecuteNonQuery();

        conn.close();

    catch (Exception)
        {
            // IF invalid data is entered, rolls back the database
            myTransaction.Rollback();
        }

当然,这是非常基本的,我使用 SQL 命令将事务提交到连接。我的问题是我可以做到这一点,但我有大约 200 个字段需要在多个表中插入。如果这是唯一的方法,我愿意做腿部工作。但我觉得有一个更简单的方法。 LINQ 中有什么可以帮助我解决这个问题的吗?

【问题讨论】:

    标签: linq datatable insert oledb


    【解决方案1】:

    如果DataTable 中的列名与目标表中的列名完全匹配,那么您也许可以使用OleDbCommandBuilder(警告:我尚未对此进行测试)。您可能会遇到问题的一个方面是源数据表的数据类型是否与目标表的数据类型不匹配(例如,如果源列数据类型都是字符串)。

    编辑 我以多种方式修改了我的原始代码。首先,我切换到在 DataTable 上使用 Merge 方法。这让我可以跳过循环使用LoadDataRow

    using ( var conn = new OleDbConnection( destinationConnString ) )
    {
        //query off the destination table. Could also use Select Col1, Col2..
        //if you were not going to insert into all columns.
        const string selectSql = "Select * From [DestinationTable]";
    
        using ( var adapter = new OleDbDataAdapter( selectSql, conn ) )
        {
            using ( var builder = new OleDbCommandBuilder( adapter ) )
            {
                conn.Open();
    
                var destinationTable = new DataTable();
                adapter.Fill( destinationTable );
    
                //if the column names do not match exactly, then they 
                //will be skipped
                destinationTable.Merge( sourceDataTable, true, MissingSchemaAction.Ignore );
    
                //ensure that all rows are marked as Added.
                destinationTable.AcceptChanges();
                foreach ( DataRow row in destinationTable.Rows )
                    row.SetAdded();
    
                builder.QuotePrefix = "[";
                builder.QuoteSuffix= "]";
    
                //forces the builder to rebuild its insert command
                builder.GetInsertCommand();
                adapter.Update( destinationTable );
            }
        }
    }
    

    添加 另一种解决方案是使用FileHelpers 之类的框架来读取 CSV 文件并将其发布到您的数据库中。它确实有一个OleDbStorage DataLink 用于发布到 OleDb 源中。请参阅SqlServerStorage InsertRecord 示例以了解如何(最终将 OleDbStorage 替换为 SqlServerStorage)。

    【讨论】:

    • 目前我有一种与此类似的方法,但效果稍好一些。这似乎仍然很草率,但它与我得出的解决方案相似。我试图找出一些更清洁的东西。
    • @jsmith - 你为什么认为它草率?如果不使用外部库,“更清洁”的解决方案会是什么样子?任何其他方法都需要遍历列,构建插入语句,然后遍历列和行并执行插入。 IMO,这要麻烦得多,需要更多代码。我已更新我的帖子以建议您可能会发现“更清洁”的 FileHelpers。它当然应该使解析 CSV 更容易。
    • @Thomas- 我不知道为什么我认为它草率。 “这看起来很草率”是我说的。我不知道是不是,这就是我问这个问题的原因。如果我知道一个“更清洁”的解决方案,我就不会要求一个。我只是想找到最好的解决方案。现在,就是这样,但它只是感觉它可能会更好。但是,我认为我的这种感觉是错误的。
    • @jsmith - 好的。您可能会再次查看 FileHelpers,它旨在解析文件并将其推送到其他来源。
    • @Thomas- 我打算接受你的回答,但你能更正一下你的代码吗?这里的一些语法/代码不起作用。我计划自己添加一个答案,这样你就可以看到它是如何工作的。但是,如果我接受这个答案,我希望未来的人们不必通过工作来弄清楚我必须做什么,几乎所有网上都有一些小问题不起作用。所以花了一点时间才弄明白。
    【解决方案2】:

    听起来您需要将许多 .mdb 和 .csv 合并为一个 .mdb。这个答案是在这个假设下运行的,并且您可以使用 SQL Server。如果没有,请考虑下载 SQL Express。

    使用 SQL Server 充当多个数据源和目标数据存储之间的代理。将每个数据源编写为插入到 SQL Server 保存表中的脚本。当所有数据都加载到保留表中后,执行最终推送到您的目标 Access 数据存储区。

    考虑以下步骤:

    • 在 SQL Server 中,为导入的 CSV 数据创建一个保存表。

    创建表 CsvImport (客户 ID smallint, 姓氏 varchar(40), 出生日期小日期时间)

    • 创建一个存储过程,其工作是读取给定的 CSV 文件路径,并插入到 SQL Server 表中。

    CREATE PROC ReadFromCSV @CsvFilePath varchar(1000) 作为 块 插入 CsvImport FROM @CsvFilePath --'c:\some.csv' 和 ( FIELDTERMINATOR = ',', -- 你自己的特定终结符应该放在这里 ROWTERMINATOR = '\n' ) 去吧

    • 创建一个脚本来调用此存储过程为您在磁盘上的每个 .csv 文件。也许一些 Excel 技巧或文件系统 dir 管道命令可以帮助您创建这些语句。


    exec ReadFromCSV 'c:\1.csv

    • 对于每个 .mdb 数据源,创建一个临时链接服务器。


    声明 @MdbFilePath varchar(1000); 选择 @MdbFilePath = 'C:\MyMdb1.mdb'; EXEC master.dbo.sp_addlinkedserver @server = N'MY_ACCESS_DB_',@srvproduct=N'Access',@provider=N'Microsoft.Jet.OLEDB.4.0',@datasrc=@MdbFilePath

    -- grab the relevant data
    --your data's now in the table...
    INSERT CsvImport(CustomerID, 
    
    SELECT [CustomerID]
      ,[LastName]
      ,[BirthDate]
    FROM [MY_ACCESS_DB_]...[Customers]
    
    --remove the linked server 
    EXEC master.dbo.sp_dropserver @server=N'MY_ACCESS_DB_', @droplogins='droplogins'
    
    • 当您将数据导入该保存表后,请在您的 SQL Server 实例中创建一个链接服务器。这是目标数据存储。 SELECT 将数据从 SQL Server 导入 Access。


    EXEC master.dbo.sp_addlinkedserver @server = N'MY_ACCESS_TARGET', @srvproduct=N'Access', @provider=N'Microsoft.Jet.OLEDB.4.0', @datasrc='C:\Target.mdb'

    INSERT INTO [MY_ACCESS_TARGET]...[Customer]
               ([CustomerID]
               ,[LastName]
               ,[BirthDate])
    SELECT   Customer,
             LastName,
             BirthDate
    FROM     CsvImport
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-08-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多