我正在使用基于Code-First DBContext的EF5设置。
在DbMigrationsConfiguration.Seed
中我试图用默认的虚拟数据填充数据库。要完成此任务,我使用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会自动生成该值,并且DB将填充重复项; Slug
选择器允许重复,并在后续运行中产生异常(Sequence contains more than one element
)。
AddOrUpdate
方法是否打算以这种方式工作?我应该手动执行upsert吗?
答案 0 :(得分:28)
首先(尚未回答),可以使用新对象数组调用AddOrUpdate
,因此您只需创建一个City[]
类型的数组并调用context.CitySet.AddOrUpdate(cc => cc.Id, cityArray);
一次。
(编辑)的
其次,AddOrUpdate
使用标识符表达式(cc => cc.Id
)来查找与数组中的Id
具有相同Id
的城市。这些城市将会更新。将插入数组中的其他城市,但数据库将生成Id
值,因为AddOrUpdate
是标识列。它不能通过insert语句设置。 (除非您设置标识插入)。因此,当对具有标识列的表使用Slug
时,您应该找到另一种标识记录的方法,因为现有记录的Id值是不可预测的。
在您的情况下,您使用AddOrUpdate
作为Slug
的标识符,该标识符应该是唯一的(根据您的评论)。我不清楚为什么不更新匹配var n = new Product { ProductID = 999, ProductName = "Prod1", UnitPrice = 1.25 };
Products.AddOrUpdate(p => p.ProductName, n);
SaveChanges();
s的现有记录。
我设置了一个小测试:添加或更新具有Id(iedntity)和唯一名称的实体:
UnitPrice
当“Prod1”尚未出现时,会插入(忽略Id 999)
如果是,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]
不同,则会更新。
查看发出的查询,我看到EF正在寻找名称的唯一记录:
UnitPrice
接下来(当找到匹配且update [dbo].[Products]
set [UnitPrice] = 1.26
where ([ProductID] = 15)
不同时)
{{1}}
这表明EF找到了一条记录,现在使用密钥字段进行更新。
我希望看到这个例子可以说明你的情况。也许你应该监视sql语句,看看是否有意外的事情发生。
答案 1 :(得分:0)
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();