有效地根据C#列表更新数据表

时间:2015-02-12 19:50:15

标签: c# sql-server

我有一个数据库表,其实体名为' Item'。此外,我的程序中还有一个Item列表。我想根据此列表更新表。也就是说,我想从数据库表中禁用列表中不存在的项,并将剩余的项添加到数据库中。我尝试了一些方法,但它们似乎效率很低。这里有一些我试过的代码:

DbContext db = new DbContext();

List<Item> newItems = ... // contains lots of items

foreach (Item item in db.ItemSet)
{
    if (!newItems.Any(x => x.Id== item.Id))
    {
        item.Enable = false;
    }
}

db.SaveChanges();

上面的代码效率低下,导致SQL Server内存使用量扩大太多。

2 个答案:

答案 0 :(得分:2)

您可以对数据库执行查询,以仅检索尚未包含任何新项目ID的记录,并仅标记这些记录。

DbContext db = new DbContext();

List<Item> newItems = ... // contains lots of items

foreach (Item item in db.ItemSet.Where(x => !newItems.Contains(x.Id))
{
    item.Enable = false;
}

db.SaveChanges();

技术上效率仍然低,因为它不会批量更新,从而导致更新n + 1方案。但是,它比返回每个记录开始并在应用程序的内存中迭代这些记录更有效。

如果你真的想要一些有效的东西,你总是可以使用像Dapper这样的东西在一次通话中更新不包含你的ID的记录。

using Dapper;
using (var c = new SqlConnection(connectionString))
{
    c.Open();
    c.Execute(string.Format("UPDATE ItemSet SET Enable = 0 WHERE Id NOT IN ({0})",
                        BuildIds(newItems.Select(x => x.Id).ToList()));
}    

public static class SqlHelpers
{
    internal static string BuildIds<T>(IReadOnlyList<T> ids)
    {
        if (ids.Count <= 0)
            return "''";

        var agsb = new StringBuilder(string.Format("'{0}'", ids[0]));
        for (var i = 1; i < ids.Count; i++)
        {
            agsb.AppendFormat(", '{0}'", ids[i]);
        }

        return agsb.ToString();
    }
}

同样,您也可以编写一个存储过程来为您处理并直接调用它。

答案 1 :(得分:0)

我认为

列表updateEItems = db.ItemSet.Any(x =&gt; newItems.Any(y =&gt; x.Id == y.Id))

是SELECT WHERE Id IN()

的实体框架