EF Core无法将具有两个导航属性的实体更新为同一对象(其他实体)

时间:2019-05-29 11:24:54

标签: c# entity-framework .net-core

我有两个桌子。用户表有两个指向另一个(相同)实体的链接,即语言:

public class User
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public Language OrigLanguage { get; set; }
    public Language Language { get; set; }
}

public class Language
{
    public int Id { get; set; }
    public string Name { get; set; }
}

EF正确创建了表:

表“用户”:ID,名字,姓氏,语言ID,OrigLanguageId

我可以为用户添加具有相同值的OrigLanguage和Language,而不会出现任何问题。 一旦我尝试更新具有相同值的现有用户,就会收到以下错误消息:

  

InvalidOperationException:实体类型'Language'的实例   无法跟踪,因为另一个实例的键值为'{Id:   1}'已被跟踪。附加现有实体时,请确保   只能附加一个具有给定键值的实体实例。

具有以下堆栈:

  

Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap.ThrowIdentityConflict(InternalEntityEntry   条目)   Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap.Add(TKey   键,InternalEntityEntry条目,bool updateDuplicate)   Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.StartTracking(InternalEntityEntry   条目)   Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState   oldState,EntityState newState,bool acceptChanges)   Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState   实体状态,布尔值acceptChanges,可为空   forceStateWhenUnknownKey)   Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.PaintAction(EntityEntryGraphNode   节点,布尔力)   Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityEntryGraphIterator.TraverseGraph(EntityEntryGraphNode   节点,TState状态,Func   handleNode)   Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityEntryGraphIterator.TraverseGraph(EntityEntryGraphNode   节点,TState状态,Func   handleNode)   Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.AttachGraph(InternalEntityEntry   rootEntry,EntityState,entityState,bool forceStateWhenUnknownKey)   Microsoft.EntityFrameworkCore.DbContext.SetEntityState(InternalEntityEntry   条目,EntityState实体状态)   Microsoft.EntityFrameworkCore.DbContext.SetEntityState(TEntity   实体,EntityState实体状态)   Microsoft.EntityFrameworkCore.DbContext.Attach(TEntity   实体)中的Namespace.Data.Repository.UpdateAsync(T实体)   Repository.cs

在Startup.cs中,我进行了以下设置以防止跟踪:

services.AddDbContext<DocLogDBContext>(
    options => options.UseSqlServer(...)
    .UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)

在我的存储库中,有以下代码要更新:

public override async Task<User> UpdateAsync(User entity)
{
    // below two detachments have no effect
    _context.Attach(entity.OrigLanguage).State = EntityState.Detached;
    _context.Attach(entity.Language).State = EntityState.Detached;
    _context.Attach(entity).State = EntityState.Modified;
    await _context.SaveChangesAsync();
    return entity;
}

我的API控制器如下所示:

[HttpPost]
public virtual async Task<IActionResult> Edit(T model)
{
    await _repository.UpdateAsync(model);
    return Ok(model);
}

这是来自客户端的请求:

Request URL: https://localhost:44344/api/User/Edit
Request Payload: 
{
    Id: 3
    , FirstName: "Joe"
    , LastName: "Frazer"
    , Language: { Name: "english", ShortName: "en", Id: 1 }
    , OrigLanguage: { Name: "english", ShortName: "en", Id: 1 }
}

我在这里想念什么?

1 个答案:

答案 0 :(得分:1)

我们可以通过在poco类上使用“ [ForeignKey(“ xxxxx”)]”属性来解决问题。 在这里,我尝试更正以下代码:

   public class User
   {
       public int Id { get; set; }
       public string FirstName { get; set; }
       public string LastName { get; set; }
       [ForeignKey("OrigLanguage")]
       public int OrigLanguageId { get; set; }
       [ForeignKey("Language")]
       public int LanguageId { get; set; }

       public Language OrigLanguage { get; set; }
       public Language Language { get; set; }
   }