首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >AddOrUpdate的工作方式与预期不符,并且会生成重复项

AddOrUpdate的工作方式与预期不符,并且会生成重复项
EN

Stack Overflow用户
提问于 2012-12-09 01:17:40
回答 2查看 18.2K关注 0票数 19

我使用的是基于代码优先的DBContext的EF5设置。

DbMigrationsConfiguration.Seed中,我尝试用默认的虚拟数据填充DB。为了完成这个任务,我使用了DbSet.AddOrUpdate方法。

最简单的代码来说明我的目标:

代码语言:javascript
复制
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吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 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)和唯一名称的实体:

代码语言:javascript
复制
var n = new Product { ProductID = 999, ProductName = "Prod1", UnitPrice = 1.25 };
Products.AddOrUpdate(p => p.ProductName, n);
SaveChanges();

当"Prod1“还不在那里时,它被插入(忽略ID999)。

如果是,并且UnitPrice不同,则更新它。

查看发出的查询,我看到EF正在按名称查找唯一的记录:

代码语言:javascript
复制
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不同时)

代码语言:javascript
复制
update [dbo].[Products]
set [UnitPrice] = 1.26
where ([ProductID] = 15)

这表明EF找到了一条记录,现在使用key字段进行更新。

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

票数 28
EN

Stack Overflow用户

发布于 2017-11-17 13:23:52

代码语言:javascript
复制
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();
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13779836

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档