C# 使用LINQ逐个插入多个记录

C# 使用LINQ逐个插入多个记录,c#,asp.net-mvc,linq,C#,Asp.net Mvc,Linq,我正在尝试将ProductStatisticsTemp表数据复制到ProductStatistics表 var str = from a in db.ProductStatisticsTemp select a; ProductStatistics ls = new ProductStatistics(); foreach (var val in str.ToList()) { ls.Product_ID = val.Product_ID;

我正在尝试将
ProductStatisticsTemp
表数据复制到
ProductStatistics

var str = from a in db.ProductStatisticsTemp select a;

ProductStatistics ls = new ProductStatistics();

foreach (var val in str.ToList())
{                     
     ls.Product_ID = val.Product_ID;
     ls.ProductNameEn = val.ProductNameEn;
     ls.ProductNameAr = val.ProductNameAr;

     db.ProductStatistics.Add(ls);
     db.SaveChanges();
}
第一条记录可以插入,但一旦尝试插入第二条记录,就会出现以下错误

属性“Product_ID”是对象关键信息的一部分,并且 无法修改


这是因为您有一个对象实例,并尝试添加两次已添加的对象

您需要在循环中创建
ProductStatistics
的新对象

此外,您还可以在循环后仅保存一次更改,以通过仅触发一次DB通信来提高性能:

var str = from a in db.ProductStatisticsTemp select a;

foreach (var val in str.ToList())
{                     
     ProductStatistics ls = new ProductStatistics
     {
         Product_ID = val.Product_ID,
         ProductNameEn = val.ProductNameEn,
         ProductNameAr = val.ProductNameAr
     };

     db.ProductStatistics.Add(ls);
}

db.SaveChanges();

这里有一个稍微不同的方法

var products = db.ProductStatisticsTemp.Select(t => new ProductStatistics
                             {
                                 Product_ID = t.Product_ID,
                                 ProductNameEn = t.ProductNameEn,
                                 ProductNameAr = t.ProductNameAr
                             }).ToList()

db.ProductStatistics.AddRange(products);
db.SaveChanges();       

IMHO的灵感来自@Vadim Martynov

如果
产品ID
是您的主键,并且设置为递增 数据库中的密钥。不要这样做
Product\u ID=val.Product\u ID
。 应该从数据库生成密钥。你会拿到身份证的 调用保存更改后

如果使用的是
AddRange
,则可以省略
db.Configuration.AutoDetectChangesEnabled=false

有关检测更改的更多信息,请参见

AddRange()方法仅支持EF6,请参阅

AddRange将为您做的是

如果将AutoDetectChangesEnabled设置为true(这是默认设置),则在添加任何实体之前将调用一次DetectChanges,并且不会再次调用

这意味着在某些情况下,AddRange的性能可能会显著提高 比多次调用Add要好


请注意,已经处于其他状态的上下文中的实体将其状态设置为“添加”。AddRange对于已处于添加状态的上下文中的实体是不可操作的。

您需要移动
ProductStatistics ls=new ProductStatistics()
到循环内部(您可以将
db.SaveChanges();
移动到循环之后)。如果要使用同一对象,则必须重置其所有属性,但如何将数据逐行保存到表中,而不是一次?@kez主要问题是:原因是什么?您可以在循环内调用SaveChanges,但结果将是相同的,您将有额外的通信通道加载。一旦我在循环内插入
SaveChanges
,我将收到错误
在提供程序连接上启动事务时出错。查看内部异常以了解详细信息。
最好的方法是查看内部异常以了解详细信息。没有可能导致此错误的问题,我们需要更多信息来回答您的问题。另外,我很抱歉,steel不明白为什么需要分别保存每一行。我只想保存已验证的结果,不想插入无效的其他结果
 try
 {
   var str = from a in db.ProductStatisticsTemp select a;

   //This will improve some performance
   db.Configuration.AutoDetectChangesEnabled = false;

   foreach (var val in str.ToList())
   {                     
      ProductStatistics ls = new ProductStatistics
      {

         Product_ID = val.Product_ID,
         ProductNameEn = val.ProductNameEn,
         ProductNameAr = val.ProductNameAr
     };

     //use AddRange or Add based on your EF Version.
     db.ProductStatistics.Add(ls);
   }

  db.SaveChanges();
 }
 finally
 {
      db.Configuration.AutoDetectChangesEnabled = true;
 }
db.ProductStatistics.AddRange(products);