为什么这个EF upsert逻辑会导致删除而不是更新?

时间:2013-06-28 11:55:01

标签: c# entity-framework

以下代码会导致删除而不是更新。

我的问题是:这是我对实体框架编码方式的错误还是我应该怀疑其他内容?

更新:我的工作正常,但我现在已经提出原始版本和工作版本的问题,希望我能学到一些我不了解的内容。 EF

在此,原始的非工作代码,当数据库是新的时,SearchDailySummary对象的所有添加成功,但是第二次,当我的代码应该执行更新时,最终结果是数据库中的一个空表,即这个逻辑设法是等价的。删除每个实体。

    //Logger.Info("Upserting SearchDailySummaries..");
    using (var db = new ClientPortalContext())
    {
        foreach (var item in items)
        {
            var campaignName = item["campaign"];

            var pk1 = db.SearchCampaigns.Single(c => c.SearchCampaignName == campaignName).SearchCampaignId;
            var pk2 = DateTime.Parse(item["day"].Replace('-', '/'));

            var source = new SearchDailySummary
            {
                SearchCampaignId = pk1,
                Date = pk2,
                Revenue = decimal.Parse(item["totalConvValue"]),
                Cost = decimal.Parse(item["cost"]),
                Orders = int.Parse(item["conv1PerClick"]),
                Clicks = int.Parse(item["clicks"]),
                Impressions = int.Parse(item["impressions"]),
                CurrencyId = item["currency"] == "USD" ? 1 : -1 // NOTE: non USD (if exists) -1 for now
            };

            var target = db.Set<SearchDailySummary>().Find(pk1, pk2) ?? new SearchDailySummary();
            if (db.Entry(target).State == EntityState.Detached)
            {
                db.SearchDailySummaries.Add(target);
                addedCount++;
            }
            else
            {
                // TODO?: compare source and target and change the entity state to unchanged if no diff
                updatedCount++;
            }

            AutoMapper.Mapper.Map(source, target);

            itemCount++;
        }

        Logger.Info("Saving {0} SearchDailySummaries ({1} updates, {2} additions)", itemCount, updatedCount, addedCount);
        db.SaveChanges();
    }

以下是工作版(虽然我并非100%优化,但只要我将其批量处理,它就可以正常运行并且表现良好一组500个或更少的项目 - 之后它会以指数方式减速,但我认为这可能是一个不同的问题/主题... ...

    //Logger.Info("Upserting SearchDailySummaries..");
    using (var db = new ClientPortalContext())
    {
        foreach (var item in items)
        {
            var campaignName = item["campaign"];

            var pk1 = db.SearchCampaigns.Single(c => c.SearchCampaignName == campaignName).SearchCampaignId;
            var pk2 = DateTime.Parse(item["day"].Replace('-', '/'));

            var source = new SearchDailySummary
            {
                SearchCampaignId = pk1,
                Date = pk2,
                Revenue = decimal.Parse(item["totalConvValue"]),
                Cost = decimal.Parse(item["cost"]),
                Orders = int.Parse(item["conv1PerClick"]),
                Clicks = int.Parse(item["clicks"]),
                Impressions = int.Parse(item["impressions"]),
                CurrencyId = item["currency"] == "USD" ? 1 : -1 // NOTE: non USD (if exists) -1 for now
            };

            var target = db.Set<SearchDailySummary>().Find(pk1, pk2);
            if (target == null)
            {
                db.SearchDailySummaries.Add(source);
                addedCount++;
            }
            else
            {
                AutoMapper.Mapper.Map(source, target);
                db.Entry(target).State = EntityState.Modified;
                updatedCount++;
            }

            itemCount++;
        }

        Logger.Info("Saving {0} SearchDailySummaries ({1} updates, {2} additions)", itemCount, updatedCount, addedCount);
        db.SaveChanges();
    }

在我脑海中不断涌现的是,Entry(entity)Find(pk)方法可能会产生一些副作用?我应该咨询文档,但任何建议都表示赞赏..

enter image description here

1 个答案:

答案 0 :(得分:1)

这是我的一个小小的假设(没有查看你的模型/实体),但看看这个块内发生了什么(看看这里附加的对象是否与删除有关):

if (db.Entry(target).State == EntityState.Detached)
{
    db.SearchDailySummaries.Add(target);
    addedCount++;
}

您的分离对象将无法使用其导航属性来查找其相关对象;你将重新附加一个处于潜在冲突状态的对象(没有正确的关系)。

你还没有提到上面被删除的内容,所以我可能会离开。刚离开,所以这有点匆忙,希望那里有一些有用的东西。