我使用的是基于代码优先的DBContext的EF5设置。
在DbMigrationsConfiguration.Seed
中,我尝试用默认的虚拟数据填充DB。为了完成这个任务,我使用了DbSet.AddOrUpdate
方法。
最简单的代码来说明我的目标:
j = 0;
var cities = new[]
{
"Berlin",
"Vienna",
"London",
"Bristol",
"Rome",
"Stockholm",
"Oslo",
"Helsinki",
"Amsterdam",
"Dublin"
};
var cityObjects = new City[cities.Length];
foreach (string c in cities)
{
int id = r.NextDouble() > 0.5 ? 0 : 1;
var city = new City
{
Id = j,
Name = c,
Slug = c.ToLowerInvariant(),
Region = regions[id],
RegionId = regions[id].Id,
Reviewed = true
};
context.CitySet.AddOrUpdate(cc => cc.Id, city);
cityObjects[j] = city;
j++;
}
我尝试使用/省略Id
字段以及使用Id
/Slug
属性作为更新选择器。
运行Update-Database
时,Id
字段将被忽略,该值将由SQL Server自动生成,并且数据库中将填充重复项;Slug
选择器允许重复项,并且在后续运行时会产生异常(Sequence contains more than one element
)。
AddOrUpdate
方法是这样工作的吗?我应该手动执行upsert吗?
发布于 2012-12-09 06:15:59
首先(目前还没有答案),可以用一个新对象数组调用AddOrUpdate
,因此您只需创建一个City[]
类型的数组并调用context.CitySet.AddOrUpdate(cc => cc.Id, cityArray);
一次。
(编辑)
其次,AddOrUpdate
使用标识符表达式(cc => cc.Id
)查找与数组中的城市具有相同Id
的城市。这些城市将会更新。数组中的其他城市将被插入,但它们的identity值将由数据库生成,因为Id
是一个Id
列。它不能由insert语句设置。(除非将Identity Insert设置为on)。因此,当对具有标识列的表使用AddOrUpdate
时,您应该找到另一种方法来标识记录,因为现有记录的ID值是不可预测的。
在本例中,您使用Slug
作为AddOrUpdate
的标识符,它应该是唯一的(根据您的注释)。我不清楚为什么这不能用匹配的Slug
更新现有记录。
我设置了一个小测试:添加或更新一个具有Id (iedntity)和唯一名称的实体:
var n = new Product { ProductID = 999, ProductName = "Prod1", UnitPrice = 1.25 };
Products.AddOrUpdate(p => p.ProductName, n);
SaveChanges();
当"Prod1“还不在那里时,它被插入(忽略ID999)。
如果是,并且UnitPrice
不同,则更新它。
查看发出的查询,我看到EF正在按名称查找唯一的记录:
SELECT TOP (2)
[Extent1].[ProductID] AS [ProductID],
[Extent1].[ProductName] AS [ProductName],
[Extent1].[UnitPrice] AS [UnitPrice]
FROM [dbo].[Products] AS [Extent1]
WHERE N'Prod1' = [Extent1].[ProductName]
和下一步(当找到匹配并且UnitPrice
不同时)
update [dbo].[Products]
set [UnitPrice] = 1.26
where ([ProductID] = 15)
这表明EF找到了一条记录,现在使用key字段进行更新。
我希望看到这个例子能让你对自己的情况有所了解。也许您也应该监视sql语句,看看是否有什么意外的事情发生。
发布于 2017-11-17 13:23:52
var paidOutType = new List<PaidOutType>
{
new PaidOutType { PaidOutTypeID = 1, Code = "001", Description = "PAID OUT 1", PType = "1", Amount = 0, IsSalesSummery = true,DayFrom=1,DayTo=31 },
new PaidOutType { PaidOutTypeID = 2, Code = "002", Description = "PAID OUT 2", PType = "1", Amount = 0, IsSalesSummery = true,DayFrom=1,DayTo=31 },
new PaidOutType { PaidOutTypeID = 3, Code = "002", Description = "PAID OUT 3", PType = "1", Amount = 0, IsSalesSummery = true,DayFrom=1,DayTo=31 },
};
paidOutType.ForEach(u => smartPOSContext.PaidOutType.AddOrUpdate(u));
smartPOSContext.SaveChanges();
https://stackoverflow.com/questions/13779836
复制相似问题