【问题标题】:How update entity after adding new entity in EF Core在 EF Core 中添加新实体后如何更新实体
【发布时间】:2017-08-12 19:22:40
【问题描述】:

我有两张桌子ClientClientSecret。这些表具有以下结构:

public class Client
    {
        public int Id { get; set; }
        public string ClientId { get; set; }
        public string ClientName { get; set; }
    public List<ClientSecret> ClientSecrets { get; set; }
    }

public class ClientSecret
{
        public int Id { get; set; }
        public string Description { get; set; }
        public string Value { get; set; }
        public DateTime? Expiration { get; set; }
        public Client Client { get; set; }
}

我需要创建一个新的Client 设置ClientIdClientName 并从数据库中取回该对象的新Id

我已经尝试过了(_dbContext 是通过构造函数中的 DI 系统获取的):

var newClient = new Client();
newClient.ClientName = client.ClientName;
newClient.ClientId = client.ClientId;
_dbContext.Clients.Add(newClient);
await _dbContext.SaveChangesAsync();

var newClientId = newClient.Id;
var clientToUpdate = await _dbContext.Clients.Where(x => x.Id == newClientId).SingleOrDefaultAsync();

clientToUpdate.ClientSecrets.AddRange(secrets);
_dbContext.Clients.Update(clientToUpdate);
await _dbContext.SaveChangesAsync();

我需要首先创建一个Client,因为表ClientSecrets 需要一个ClientId 来在该表中创建新记录。

我收到此错误消息:

在行中失败:_dbContext.Clients.Update(clientToUpdate);

InvalidOperationException:实体类型“客户端”的实例不能 被跟踪,因为此类型的另一个具有相同键的实例是 已经被追踪。添加新实体时,对于大多数键类型 如果没有设置键(即如果 键属性为其类型分配了默认值)。如果你 正在为新实体显式设置键值,确保它们不会 与现有实体或为其他生成的临时值发生冲突 新实体。附加现有实体时,确保只有一个 具有给定键值的实体实例附加到上下文。

我该如何解决这个问题?

【问题讨论】:

  • 您正在使用 EF Core,就像您在编写原始 sql 查询时一样,这比 ORM 的许多优势都强

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


【解决方案1】:

无法跟踪实体类型“客户端”的实例,因为另一个 已在跟踪具有相同密钥的此类实例

已经在_dbContext.Clients.Add(newClient); 上创建了client 的实例。

您需要先分离第一个条目,然后再附加更新的条目

之后

_dbContext.Clients.Add(newClient);
await _dbContext.SaveChangesAsync();

添加分离代码

_dbcontext.Entry(newClient).State = EntityState.Detached;

【讨论】:

  • 完美运行,快速修复! :) 谢谢Ashik irsha。
  • 拯救我的一天,谢谢
  • 为什么分离不是自动的?保存提交后不解除附加可以获得什么。代码有效。我遇到了这个问题,它使用 add 和 commitsave 进行单元测试,然后进行更新
【解决方案2】:

您使用的是 EF Core,就像您编写原始 SQL 查询时一样,这比 ORM 的许多优势都要好。

ClientSecrets 不需要 ClientId,因为 EF Core 可以自己找出关系。

var newClient = new Client
{
    ClientName = client.ClientName,
    ClientId = client.ClientId,
    ClientSecrets = secrets.ToList() // or ToArray or whatever it is
};

_dbContext.Clients.Add(newClient);
await _dbContext.SaveChangesAsync();

ClientSecret 需要对Client 类的反向引用不是问题,通过将您的秘密添加到模型中,您可以建立ClientSecretClient 的关系。

现在保存时,EF Core 会知道它必须先添加 Client,然后再添加 ClientSecrets

【讨论】:

    【解决方案3】:

    您好,请添加以下内容,它适用于 2020 年 9 月 25 日星期五。 AsNoTracking 为我解决了这个问题。因为我能够更新我的。谢谢

    var clientToUpdate = await _dbContext.AsNoTracking().Clients.Where(x => x.Id == newClientId).SingleOrDefaultAsync();
    
    clientToUpdate.ClientSecrets.AddRange(secrets);
    _dbContext.Clients.Update(clientToUpdate);
    await _dbContext.SaveChangesAsync();
    

    【讨论】:

      猜你喜欢
      • 2015-01-26
      • 2018-06-29
      • 1970-01-01
      • 1970-01-01
      • 2022-10-18
      • 2013-03-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多