在EF Core中添加新实体后如何更新实体

Jen*_*nan 6 c# entity-framework entity-framework-core asp.net-core

我有两张桌子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; }
}
Run Code Online (Sandbox Code Playgroud)

我需要全部创建一个新Client集,ClientId并从数据库中ClientName获取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();
Run Code Online (Sandbox Code Playgroud)

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

我收到此错误消息:

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

InvalidOperationException:无法跟踪实体类型“客户端”的实例,因为已经跟踪了具有相同键的该类型的另一个实例。添加新实体时,对于大多数键类型,如果未设置任何键(即,如果为键属性分配了其类型的默认值),则将创建唯一的临时键值。如果您为新实体明确设置键值,请确保它们不与现有实体或为其他新实体生成的临时值冲突。附加现有实体时,请确保仅将一个具有给定键值的实体实例附加到上下文。

如何解决此问题?

Tse*_*eng 9

您正在使用 EF Core,就像您编写原始 SQL 查询时一样,这与 ORM 的许多优势相比更胜一筹。

您不需要ClientIdfor ClientSecrets,因为 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();
Run Code Online (Sandbox Code Playgroud)

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

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


小智 6

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

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

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

_dbContext.Clients.Add(newClient);
await _dbContext.SaveChangesAsync();
Run Code Online (Sandbox Code Playgroud)

添加用于分离的代码

_dbcontext.Entry(newClient).State = EntityState.Detached;
Run Code Online (Sandbox Code Playgroud)

  • 为什么脱离不是自动的?保存提交后不分离会获得什么。该代码有效。我遇到了这个问题,它通过添加和提交保存然后更新进行单元测试 (2认同)