1

ファイルからデータを挿入したり、存在する場合は更新したりするコードを実行していたときに、大きな問題が発生しました。エンティティ フレームワークを使用しています。ファイルは 16,000 行近くあります

私はそれらを挿入しようとしましたが、これを行うのに多くの時間を費やしました: 5 時間以上 x ファイル。

変更することにしましたが、開始方法がわかりません。

1000、5000、10000行ごとに保存することについて何かを読みましたが、それをしようとすると例外が発生しました。

Store update, insert, or delete statement affected an unexpected number of rows (0).
Entities may have been modified or deleted since entities were loaded. Refresh
ObjectStateManager entries.

修正しようとすると、この例外が発生しました

AcceptChanges can not continue because the object's key values ​​conflict with another
object in ObjectStateManager. Make sure that the key values ​​are unique before calling 
AcceptChanges.

これは私のコードです

//before this I passed db data to lists
foreach (var record in records)
{
    if (record != null)
    {
        try
        {
            if (!_location.Any(s => s.Id.Trim() == record.Id))
            {               
                Location l = new Location
                    {
                        Id = record.Id,
                        Name = record.Name,
                        Address = record.Address,
                        City = record.City,
                        State = record.State,
                        Zip = record.Zip.ToString(),
                        Zip2 = record.Zip2,
                        Custom1 = record.Custom1,                       
                        CreatedDate = date,
                        UpdatedDate = date
                    };

                db.location.Add(l);  
                db.SaveChanges();                              
                _location.Add(l);                                        
            }
            else
            {                                
                if (!_sales.Any(s => s.LocationId == record.Id && s.ReportDate == record.ReportDate))
                {
                    Sale s = new Sale
                    {
                        ReportDate = record.ReportDate,
                        CreatedDate = date,
                        UpdatedDate = date,
                        Amount = record.Amount,
                        LocationId = record.Id,
                    };
                    db.Sale.Add(s);  
                    db.SaveChanges();                  
                    _sales.Add(s);
                }
                else
                {

                    if (!_sales.Any(s => s.LocationId == record.Id && s.ReportDate == record.ReportDate && s.Amount == record.Amount))
                    {                       
                        if ((_sales.Where(s => s.LocationId == record.Id && s.ReportDate == record.ReportDate)).Count() == 1)
                        {                           
                            var sale = _sales.SingleOrDefault(s => s.LocationId == record.Id && s.ReportDate == record.ReportDate);
                            sale.UpdatedDate = date;
                            sale.Amount = record.Amount;
                            db.Entry(sale).State = EntityState.Modified;  
                            db.SaveChanges();                                                                   
                        }                                                
                    }
                }                                        
            }                        
        }
        catch (Exception ex)
        {

        }

    }
}

私が行った変更は次のとおりです。

すべての db.SaveChanges を foreach の最後で 1 つだけ変更すると、最初の例外が発生しました (これも 3000 でグループ化した場合)

エンティティの状態を変更すると、2 番目の例外が発生しました。

あなたの助けに感謝します。

ありがとう。

4

1 に答える 1

1

私が理解している限り、ファイルからデータにデータをインポートしたいと考えています。私が正しければ、同じ問題に直面していましたが、更新ごとに 20,000 を超えるアイテムがありました。いくつかのテストの後、私はあなたの問題を解決するかもしれない次の解決策に行き着きました:

  • EF は、大量のデータのインポートに対して非常に遅い
  • そのため、SqlBulkCopy-Command を使用して追加のインポート テーブルにデータをインポートし、ストアド プロシージャによってデータベース内のインポートされたデータを処理しました。データをインポートする方法は次のようになります。

private void DoMassDataImport(DataTable tab)
 {            
    var conn = new SqlConnection(this.sqlConnectionString);
    try
    {
        if (conn.State != ConnectionState.Open)
        {
            conn.Open();
        }

        SqlTransaction transaction = conn.BeginTransaction();

        using (SqlBulkCopy copy = new SqlBulkCopy(conn, SqlBulkCopyOptions.Default, transaction))
        {
            copy.BulkCopyTimeout = 10000;
            copy.DestinationTableName = "dbo.TargetTable";
            copy.WriteToServer(tab);
        }
        transaction.Commit();
        result.Success = true;                
    }
    catch (Exception ex)
    {
        result.Success = false;
        this.LogEvent(ex.Message + Environment.NewLine + ex.StackTrace);
    }
    finally
    {
        conn.Close();                
    }
}
  • ストアド プロシージャはコードから呼び出すことができます。処理に 1 分以上かからない場合は EF を使用できますが、それ以上かかる場合は、次のような単純な SQL コマンドを使用することを検討する必要があります。

private void ProcessImportedData()
{
    SqlConnection connection = null;    
    try
    {
        connection = new SqlConnection(this.sqlConnectionString);
        if (connection.State != ConnectionState.Open)
        {
            connection.Open();
        }

        SqlTransaction transaction = connection.BeginTransaction();
        using (SqlCommand processingCommand = connection.CreateCommand())
        {
            processingCommand.Transaction = transaction;
            processingCommand.CommandTimeout = 10000;
            processingCommand.CommandText = "dbo.StoredProcedure ";
            processingCommand.CommandType = CommandType.StoredProcedure;
            processingCommand.ExecuteNonQuery();            
            result.Success = true
        }

        transaction.Commit();
    }
    catch (Exception ex)
    {
        result.Success = false;     
    }
    finally
    {
        if (connection != null)
        {
            connection.Close();

        }
    }
}
  • このアプローチを使用すると、データのインポートにかかる時間が 5 時間以上から 5 分未満に短縮されました
于 2013-09-08T19:47:09.020 に答える