Home > OS >  Entity Framework n to n relationship add object to another object
Entity Framework n to n relationship add object to another object

Time:11-11

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.

  • Related