c# - 使用 LINQ to Entities 向表中插入多条记录的正确方法

标签 c# entity-framework ado.net linq-to-entities

正如我们许多人所做的那样,我设置了一个简单的循环来从数据库中添加多条记录。一个典型的例子是这样的:

方法一:

// A list of product prices
List<int> prices = new List<int> { 1, 2, 3 };

NorthwindEntities NWEntities = new NorthwindEntities();

foreach (int price in prices)
{
   Product newProduct = new Product();
   newProduct.Price = price;
   NWEntities.Products.AddObject(newProduct);
}

NWEntities.SaveChanges();

然而,当我第一次设置循环时,我凭直觉写道:

方法二:

Product newProduct = new Product();
   
foreach (int price in prices)
{
   newProduct.Price = price;
   NWEntities.Products.Add(newProduct);
}

在阅读了一些内容后,一些人提到如果使用方法二,只会向表中添加一条记录。这似乎违反直觉。加载新插入的是 Add() 函数,而且我认为,在每次调用传入的数据后创建一个对象。在循环外部声明我的 Product 对象似乎可以更好地利用资源,因为每次调用中消耗的唯一开销是对象实例属性的重新分配,而不是对象实例本身的重建。

谁能解释一下?我找不到另一篇直接处理这个问题的帖子。如果有,请指出。

最佳答案

只需将新产品的实例化移动到循环内即可。您编写的代码将多次添加一个实例,这不会产生您想要的东西......您需要每个产品的单独实例...... Add 方法不会制作副本,它将对象附加到上下文并将其标记为插入。

foreach (int price in prices)
{
   Product newProduct = new Product();
   newProduct.Price = price;
   NWEntities.Products.Add(newProduct);
}

要更明确地了解正在发生的事情,请考虑以下内容:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Try to reuse same Instance:");
        using (var ctx = new AdventureWorksEntities())
        {
            List<int> ids = new List<int> {1, 2, 3}; 
            Product p1 = new Product();
            Product reference = p1;
            Product p2;
            Console.WriteLine("Start Count: {0}", ctx.Products.Count());
            foreach (var id in ids)
            {
                p1.ProductID = id;
                p2 = ctx.Products.Add(p1);
                Console.WriteLine("p1 = p2 ? {0}", p1 == p2);
                Console.WriteLine("p2 = reference? {0}", p2 == reference);
                Console.WriteLine("State: {0}", ctx.Entry(p1).State);
                var changes = ctx.ChangeTracker.Entries<Product>();
                Console.WriteLine("Change Count: {0}", changes.Count());
            }
        }
        Console.WriteLine();
        Console.WriteLine("Distinct Instances:");
        using (var ctx = new AdventureWorksEntities())
        {
            List<int> ids = new List<int> { 1, 2, 3 };
            Product p2;
            foreach (var id in ids)
            {
                var p1 = new Product {ProductID = id};
                p2 = ctx.Products.Add(p1);
                Console.WriteLine("p1 = p2 ? {0}", p1 == p2);
                Console.WriteLine("State: {0}", ctx.Entry(p1).State);
                var changes = ctx.ChangeTracker.Entries<Product>();
                Console.WriteLine("Change Count: {0}", changes.Count());
            }
        }

        Console.ReadLine();
    }
}

在第一个循环中,您重复使用了相同的产品实例,但是当您将它添加到上下文中时,您每次都只是使用相同的引用。您可以看到无论循环执行了多少次,更改计数都保持为 1。当然,如果您要调用 ctx.SaveChanges(),只会保存最后的值。

在第二个版本中,更改计数每次都会正确递增,您将调用 SaveChanges 来保存所有不同的实体,正如您所期望的那样。

关于c# - 使用 LINQ to Entities 向表中插入多条记录的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22489118/

相关文章:

c# - 使用 EF CodeFirst 和 DRY 原则进行重复验证

c# - 如何通过SqlConnection获取最后执行的SQL查询?

c# - 正则表达式在 C# 中匹配 2 个字母加 6 位数字

c# - 让 Messagebox 显示一个变量

c# - Windows.Forms.RichTextBox 丢失表格背景颜色

c# - 在 MVC Entity Framework 中 PUT 复杂实体类型的正确方法是什么

c# - 数据表选择方法 "not intended to be used"?

c# - 如何使用 Linq 选择列名

postgresql - 如何在 NpgSql 连接字符串中指定 ApplicationName

c# - 替换系统对象的策略