19

我正在使用基于代码优先 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 吗?

4

2 回答 2

28

首先(还没有答案),AddOrUpdate可以使用新对象数组调用,因此您只需创建一个类型数组City[]并调用context.CitySet.AddOrUpdate(cc => cc.Id, cityArray);一次。

(已编辑)

其次,AddOrUpdate使用标识符表达式 ( cc => cc.Id) 查找与Id数组中的城市相同的城市。这些城市将被更新。数组中的其他城市将被插入,但它们的Id值将由数据库生成,因为Id它是一个标识列。它不能由插入语句设置。(除非您将身份插入设置为打开)。因此,当使用AddOrUpdate带有标识列的表时,您应该找到另一种识别记录的方法,因为现有记录的 Id 值是不可预测的。

在您的情况下,您用作Slug的标识符AddOrUpdate,它应该是唯一的(根据您的评论)。我不清楚为什么不使用匹配Slug的 s 更新现有记录。

我设置了一个小测试:添加或更新具有 Id (iedntity) 和唯一名称的实体:

var n = new Product { ProductID = 999, ProductName = "Prod1", UnitPrice = 1.25 };
Products.AddOrUpdate(p => p.ProductName, n);
SaveChanges();

当“Prod1”尚不存在时,将其插入(忽略 Id 999)。
如果它是并且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 找到了一条记录,现在使用关键字段进行更新。

我希望看到这个例子能对你的情况有所了解。也许您也应该监视 sql 语句,看看是否有任何意外发生。

于 2012-12-08T22:15:59.073 回答
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();
于 2017-11-17T05:23:52.287 回答