I have a two tables Client
and ClientSecret
. The tables have following structure:
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; }
}
I need for of all create a new Client
set the ClientId
and ClientName
and get back a new Id
of this object from DB.
I have tried this (_dbContext
is getting via DI system in the constructor):
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();
I need first create a Client
because the table ClientSecrets
needs a ClientId
for creating a new records into this table.
I got this error message:
Failed the in the row with: _dbContext.Clients.Update(clientToUpdate);
InvalidOperationException: The instance of entity type 'Client' cannot be tracked because another instance of this type with the same key is already being tracked. When adding new entities, for most key types a unique temporary key value will be created if no key is set (i.e. if the key property is assigned the default value for its type). If you are explicitly setting key values for new entities, ensure they do not collide with existing entities or temporary values generated for other new entities. When attaching existing entities, ensure that only one entity instance with a given key value is attached to the context.
How can I fix this issue?
The instance of entity type 'Client' cannot be tracked because another instance of this type with the same key is already being tracked
there is already an instance of client
created on _dbContext.Clients.Add(newClient);
.
you need to Detach the first entry before attaching your updated entry
after
_dbContext.Clients.Add(newClient);
await _dbContext.SaveChangesAsync();
add code for detaching
_dbcontext.Entry(newClient).State = EntityState.Detached;
You are using EF Core like when you write raw SQL queries, which kind of beats many of the advantages of an ORM.
You don't need the ClientId
for ClientSecrets
, because EF Core can figure out the relations itself.
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();
It's not a problem that ClientSecret requires a back reference to the Client
class, by adding your secrets to the model, you establish a relationship of ClientSecret
to Client
.
When you save now, EF Core will know it has first to add the Client
and then add the ClientSecret
s