简体   繁体   English

使用EF多实体保存或更新数据

[英]Saving or updating data using ef multiple entity

I have a big problem when I was doing my code which involve insert data, or update if this exists, from a file. 在执行涉及从文件插入数据或更新(如果存在)数据的代码时,我遇到了一个大问题。 I'm using entity framework. 我正在使用实体框架。 files are near to 16 000 rows 文件接近16000行

I tried to insert them but I spent a lot of time doing this: more than 5 hour x file. 我试图插入它们,但是我花了很多时间这样做:x文件超过5个小时。

I decided to change it but i dont know how to start. 我决定更改它,但我不知道如何开始。

I read something about save each 1000, 5000, 10000 row, but I got and exception when i try to do it. 我读了一些关于保存每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.

and when I tried to fix it I got this exception 当我尝试修复它时,出现此异常

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.

this is my code 这是我的代码

//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)
        {

        }

    }
}

The changes I've done was: 我所做的更改是:

change all db.SaveChanges for only one at the end of the foreach, and I got the First exception (also when I group them by 3000) 在foreach末尾仅更改所有db.SaveChanges,我得到了第一个异常(同样当我将它们分组为3000时)

change the entity state, and I got the second exception. 更改实体状态,我得到了第二个例外。

I'llappreciate your help, 我会感谢您的帮助,

thanks. 谢谢。

As far as I understand, you want to import data from file to data. 据我了解,您希望将数据从文件导入到数据。 If I'a right, I was facing the same Problem, but with over 20,000 items per update. 如果我是对的,那么我也面临着同样的问题,但是每次更新有超过20,000个项目。 After some test I came to following solution which may solves your problem: 经过测试,我得出以下解决方案,可以解决您的问题:

  • the EF is much to slow for mass data Import EF对于海量数据导入而言要慢得多
  • so I used the SqlBulkCopy-Command to import the data in an extra import table and proccessed the imported data inside the database by stored procedures. 因此,我使用SqlBulkCopy-Command将数据导入额外的导入表中,并通过存储过程在数据库内部处理了导入的数据。 A method to do Import the data could look like this: 导入数据的方法如下所示:

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();                
    }
}
  • the stored procedures can be called from code, if the processing does not take longer than 1 Minute you could use the EF, but if it takes longer you should consider to use plain SQL commands like this: 可以从代码中调用存储过程,如果处理时间不超过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();

        }
    }
}
  • using this approach reduced the time for the data Import from more than 5 hours to less than 5 minutes 使用这种方法可以将数据导入时间从超过5小时减少到少于5分钟

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM