I have a Model with Clients:
public class Client
{
[Key]
public int id { get; set; }
[Required]
public string? Hostname { get; set; }
public ICollection<Software>? Softwares { get; set; }
}
And a Model with Software:
public class Software
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int id { get; set; }
public string Name { get; set; }
public ICollection<Client>? Clients { get; set; }
}
This is supposed to be an n to n connection. How can I add software to my clients?
What I've tried:
public async void add(Software software)
{
using (var repo = new ClientRepository(contextFactory.CreateDbContext()))
{
client.Softwares.Add(software);
await repo.Save(client);
}
Repository:
public async Task Save(Client client)
{
_context.Clients.Update(client);
_context.SaveChanges();
}
}
This works for the first software I add, but gives me the following error if I try to add a second one:
SqlException: Violation of PRIMARY KEY constraint 'PK_ClientSoftware'. Cannot insert duplicate key in object 'dbo.ClientSoftware'. The duplicate key value is (7003, 5002).
CodePudding user response:
Q: Do you make a new one with new() every time?
A: no, its a software that already exists
Then that is the error.
The first SaveChanges() will start tracking it as Existing. You can check: The Id will be != 0.
When you then later add it to the same Client you'll get the duplicate error.
So somewher in your code:
await add(software); // existing
software = new Software(); // add this
Related, change:
public async void add(Software software)
to
public async Task Add(Software software)
Always avoid async void
.
CodePudding user response:
It seems you are adding more than one relation of the same. Before adding software to a client, make sure a relation does not exist yet, then you can go ahead and add software to client.
Also, you can improve your entities. Use better naming for the primary keys and add [Key]
attribute to Software
class as well.
Client
:
public class Client
{
public Client()
{
Softwares = new HashSet<Software>();
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ClientId { get; set; }
[Required]
public string Hostname { get; set; }
public ICollection<Software> Softwares { get; set; }
}
Software
:
public class Software
{
public Software()
{
Clients = new HashSet<Client>();
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int SoftwareId { get; set; }
public string Name { get; set; }
public ICollection<Client> Clients { get; set; }
}
Check if relation already exists:
// Get the client including its related softwares
var client = dbContext.Clients.Include(x => x.Softwares)
.FirstOrDefault(x => x.Hostname == "Ibrahim");
if (client != null)
{
// Check with unique property such as name of software
// If it does not exist in this current client, then add software
if (!client.Softwares.Any(x => x.Name == software.Name))
client.Softwares.Add(software);
dbContext.SaveChanges();
}
Note: If you update your entities, remember to create new migration and database.