【问题标题】:Properly and efficiently update hundreds of records in sql server db table from .net c# application loop从.net c#应用程序循环正确有效地更新sql server db表中的数百条记录
【发布时间】:2016-05-23 18:06:29
【问题描述】:

我使用 Entity Framework 6 已经有一段时间了,通常我一次更新 1 条记录。

但是,我需要遍历所有用户,300 - 1,000 个用户

更新数据库中的几列是否会非常低效和缓慢。使用 EF6.x 吗?我应该改用 ADO.NET 还是通过网络发送某种对象,进行一些批量更新??

目前我是这样更新的

rpmuser.usr_id = user;
rpmuser = db.rpm_usr.Find(rpmuser.usr_id);
rpmuser.lst_pwd_chg_dtm = dateTime;
rpmuser.cre_dtm = dateTime;

rpmuser.usr_pwd = hash;
rpmuser.salt = salt;

db.SaveChanges();

所以本质上,如果我循环访问其他用户,那可以吗?我还能如何通过批量更新来做到这一点?

for( ....  ) {
  // different user id 
  // all the other needed poco model changes above... etc.
  // db.SaveChanges()
}

【问题讨论】:

标签: c# sql-server entity-framework entity-framework-6 bulkinsert


【解决方案1】:

您可以使用以下代码来测试:

static void Main(string[] args)
{
    CreateAndSeedTheDatabase(); // Step 1: run this
    //UpdateAllOfTheProducts(); // Step 2: Comment out the above line and uncomment and run this line
}

static void CreateAndSeedTheDatabase()
{
    Context context = new Context();
    context.Database.Initialize(true);

    Product product;
    for (int i = 0; i < 1000; i++)
    {
        product = new Product() { ProductId = i, Name = "Product" + i };
        context.Products.Add(product);
    }
    context.SaveChanges();
}

static void UpdateAllOfTheProducts()
{
    Context context = new Context();
    Product[] products = context.Products.ToArray();
    foreach (Product product in products)
    {
        product.Name = product.ProductId + "Product";
    }
    context.SaveChanges();
}

public class Context : DbContext
{
    public Context()
    {
        Database.SetInitializer(new DropCreateDatabaseIfModelChanges<Context>());
    }
    public DbSet<Product> Products { get; set; }
}

public class Product
{
    public int ProductId { get; set; }
    public string Name { get; set; }
}

}

【讨论】:

  • 我需要插入的不是新记录,而是更新,我试图在不更新所有列的情况下执行 .Add(model) 和 SaveChanges() 并且 EF 想告诉 sql server 它是一个 INSERT 语句,因此我通过在 SaveChanges() 之前使用 Find() 将其更改为工作,所以我认为我不应该在 for 循环中执行 SaveChanges() ,但是会通过的 Find(user) 呢使用传入的用户参数等...
  • 您是否尝试在控制台应用程序中运行此代码? UpdateAllOfTheProducts 方法更新由 CreateAndSeedTheDatabase 方法创建的数据库中的所有现有记录。
【解决方案2】:

要正确有效地更新数百条记录,您需要尽可能减少数据库往返。

在您的情况下,您有两种方法可以进行繁重的数据库往返

查找方法

对于您需要更新的每个用户,您都在进行数据库往返。有多种方法可以快速减少这种情况。

  • 加载所有用户并使用带有键“usr_id”的字典来只进行一次数据库往返(如果数据库不包含数百万用户,则工作得很好!)

  • 创建一个包含所有“usr_id”的列表并使用包含方法一次检索所有用户

例子:

// Work well if the database doesn't contain to much users
var userDict = db.rpm_usr.ToList().ToDictionary(x => x.usr_id);


// Be careful, the list cannot contains more than 2099 items (SQL Parameters limit = 2100)
var userDict = db.rpm_usr.Where(x => ids.Contains(x.usr_id)).ToDictionary(x => x.usr_id);

在这两种解决方案中,只会执行一次数据库往返,您可以非常高效地从字典中检索用户。

SaveChanges 方法

SaveChanges 方法为要更新的每条记录执行数据库往返。所以如果更新 1000 个用户,会进行 1000 次数据库往返,非常慢。

免责声明:我是项目的所有者Entity Framework Extensions

此项目允许执行 BulkSaveChanges 和 BulkUpdate 以显着提高性能:

for( ....  ) {
  // different user id 
  // all the other needed poco model changes above... etc.
  db.BulkSaveChanges()
}

for( ....  ) {
  // different user id 
  // all the other needed poco model changes above... etc.
  db.BulkUpdate(users)
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-05
    • 1970-01-01
    • 1970-01-01
    • 2018-10-01
    • 2023-03-27
    相关资源
    最近更新 更多