1

我正在将使用 EF Core 2.2 的 ASP.NET Core 2.2 应用程序迁移到 ASP.NET Core 3.0 和 EF Core 3.0。

在一种特定方法中,后端从前端接收 DTO,并使用 Automapper 将其转换为等效的实体类型,将其附加到 DbContext 并保存。这在 EF Core 2.2 上完美运行,但在 EF Core 3.0 上失败并显示以下消息:

The instance of entity type 'ServiceProvider' cannot be tracked because another
instance with the same key value for {'Id'} is already being tracked

这是有问题的代码:

var sqresponse = _mapper.Map<SurveyQuestionResponse>(sqresponseDTO);

_context.Attach(sqresponse); // <=== Throws exception
_context.SaveChanges();

以下是具有相关类的实体:

public class SurveyQuestionResponse
{
    public int? Id { get; set; }
    public List<Answer> Answers { get; set; } = new List<Answer>();
}

public class Answer
{
    public int? Id { get; set; }
    public int SurveyQuestionResponseId { get; set; }
    public ServiceProvider ServiceProvider { get; set; }
}

从前端传递给该方法的数据有两个Answer,它们都包含一个ServiceProviderwith Id = 56

{
    answers: [
        {
            // some more properties here
            serviceProviderId: 56,
            serviceProvider: { id: 56, name: "Foo" },
        },
        {
            // some more properties here
            serviceProviderId: 56,
            serviceProvider: { id: 56, name: "Foo" },
        }
    ]
}

这两个ServiceProvider实体应该存在于数据库中;在这种情况下,我需要Answer与现有ServiceProvider实体相关联,{Id: 56} 这对于 EntityFramework Core 3.0 来说似乎是一个问题,但对于 EF Core 2.2 来说非常好。

我怀疑这与这个重大变化有关:DetectChanges 尊重商店生成的键值ServiceProvider,但我认为提议的缓解将解决这个特定问题,但在尝试插入新实体时会创建另一个问题。我对么?

如何使它与 EF Core 3.0 一起使用?

4

2 回答 2

0

这在 EFCore 2.2 中也不起作用,因此您的使用/测试用例必须有足够的不同。

提交的 JSON 将被反序列化为您的实体对象。相关属性serviceProvider将为每个答案实体对象反序列化/具体化一个实体对象 - 这意味着,在您的示例中,两个答案对象将引用具有相同 ID 的两个不同ServiceProvider对象。当附加它们的引用answer对象时,EFCore 还将尝试附加它们的引用ServiceProvider对象,但尝试附加第二个答案对象将引发您收到的错误,因为上下文已经在跟踪ServiceProvider具有相同 ID 的实体,而不是同一个对象。

在尝试将实体添加到上下文之前,您需要检查实体是否已被跟踪,这意味着您不能盲目地将 DTO 附加到上下文。

在通过 附加answer对象之前DTO,首先检查是否存在具有相同 ID 的该类型的实体对象已被上下文跟踪,并将该对象分配给serviceProvider属性:

var attachedServiceProvider = dbContext.ServiceProviders
    .Local
    .FirstOrDefault(sp => sp.Id = answerObject.serviceProvider.Id);

if( null == attachedServiceProvider )
{
    dbContext.Attach(serviceProvider);
    attachedServiceProvider = serviceProvider;
}

answerObject.serviceProvider = attachedServiceProvider;
于 2019-11-12T19:01:44.557 回答
0

我最终通过确保仅answer.ServiceProviderId填写并answer.ServiceProvidernull附加时解决了它。

传递到后端的 JSON 现在看起来像这样,然后:

{
    answers: [
        {
            // some more properties here
            serviceProviderId: 56,
            serviceProvider: null,
        },
        {
            // some more properties here
            serviceProviderId: 56,
            serviceProvider: null,
        }
    ]
}

有了这个,调用_context.Attach(...)_context.SaveChanges()工作没有问题。

于 2019-11-13T13:02:38.223 回答