see*_*uit 29 c# ado.net linq-to-entities entity-framework
正如我们许多人所做的那样,我设置了一个简单的循环来从数据库添加多个记录.一个典型的例子是这样的:
// 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();
Run Code Online (Sandbox Code Playgroud)
然而,当我第一次设置循环时,我直观地写道:
Product newProduct = new Product();
foreach (int price in prices)
{
newProduct.Price = price;
NWEntities.Products.Add(newProduct);
}
Run Code Online (Sandbox Code Playgroud)
在做了一点阅读之后,几个人提到如果使用方法II,则只会在表格中添加一条记录.这似乎反直觉.这是加载新插入的Add()函数,我认为,在每次调用传入数据后创建一个对象.在循环外声明我的Product对象似乎更好地利用资源,因为这是消耗的唯一开销.每次调用都是对象实例属性的重新赋值,而不是对象实例本身的重构.
有人可以澄清一下吗?我找不到另一个直接处理这个问题的帖子.如果有人在那里请指出.
ter*_*ryt 24
只需在循环中移动新产品的实例化即可.您编写的代码将多次添加单个实例,这不会产生您所需的内容...您需要每个产品的单独实例... Add方法不会复制,它会将对象附加到上下文并标记它以便插入.
foreach (int price in prices)
{
Product newProduct = new Product();
newProduct.Price = price;
NWEntities.Products.Add(newProduct);
}
Run Code Online (Sandbox Code Playgroud)
要了解发生了什么,请更多地明确考虑以下内容:
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();
}
}
Run Code Online (Sandbox Code Playgroud)
在第一个循环中,您将重用相同的产品实例,但是当您将其添加到上下文时,您每次只使用相同的引用.无论循环执行多少次,您都可以看到更改计数保持为1.当然,如果你要调用ctx.SaveChanges(),只会保存最后的值.
在第二个版本中,每次更改计数都会正确递增,并且您将调用SaveChanges将保存所有不同的实体,如您所料.
小智 15
+1对于Terryt的回答.你需要坚持方法一或类似的东西.
在Entity framework 6版本中,有一种新方法可以在一个语句中添加一组数据.这是AddRange方法.
我想补充一点,当你想根据现有列表(或IEnumerable)添加实体时,我发现AddRange方法很优雅.
在你的情况下,可以这样做:
NWEntities.Products.AddRange(
Prices.Select(priceitem =>
new Product{price = priceitem})
)
Run Code Online (Sandbox Code Playgroud)
在语义上,这应该类似于您的方法1.一个Product对象在价目表中按价格实例化.然而,有一个区别,它是匿名完成的,因此没有明确定义的引用变量指向新对象.
如果性能很重要,那么这个问题可能会为您提供更多信息:实体框架中最快的插入方式
希望这会给你一些帮助.
| 归档时间: |
|
| 查看次数: |
53504 次 |
| 最近记录: |