Behind the scenes EFCore 5 will be creating a linking table, likely called TemplateComponentTemplates or TemplateTemplateComponents. This table will solely consist of a TemplateId and a TemplateComponentId. To append any additional columns to this table such as a quantity or accommodate support for multiple components on the same template, you will need to explicitly declare this joining entity.
To simplify the naming convention I've renamed what you call a TemplateComponent to Component so that TemplateComponent will reflect the joining entity.
The first step is to update our "many" reference type to use the joining entity:
public class Template
{
[Key]
public int Id { get; set; }
[Required]
public string ImagePath{ get; set; }
public virtual ICollection<TemplateComponent> TemplateComponents { get; set; } = new List<TemplateComponent>();
}
public class Component
{
[Key]
public int Id { get; set; }
[Range(0,12)]
public int Space{ get; set; }
public virtual ICollection<TemplateComponent> TemplateComponents { get; set; } = new List<TemplateComponent>();
}
"Many"-side navigation properties should be declared as virtual ICollection<TEntity>
so that EF can properly wire up proxies for change tracking.
Now, depending on how you want the multiplicity between template and component expressed, the TemplateComponent entity could be something like:
public class TemplateComponent
{
[Key, Column(Order-0), ForeignKey(Template)]
public int TemplateId { get; set; }
[Key, Column(Order-1), ForeignKey(Component)]
public int Component { get; set; }
public int Quantity { get; set; } = 1;
public virtual Template Template { get; set; }
public virtual Component Component { get; set; }
}
There would be one linking record between a Component and particular template but with an additional field to express a multiplier or quantity of that template and component association.
Or instead if you want to support a join where multiple instances of this joining record can be set up for each combination (likely with additional information columns for each combination):
public class TemplateComponent
{
[Key]
public int Id { get; set; }
[ForeignKey(Template)]
public int TemplateId { get; set; }
[ForeignKey(Component)]
public int Component { get; set; }
public virtual Template Template { get; set; }
public virtual Component Component { get; set; }
}
The difference here is that TemplateComponent gets its own unique PK rather than the composite key, allowing for a Component to have more than one ComponentTemplate for the same Template.
In both cases the mapping of the relationship between the entities changes a bit. Instead of:
modelBuilder.Entity<Template>()
.HasMany(x => x.Components)
.WithMany(x => x.Templates);
Where EF Core auto-magically wires up a joining table, you need to be a bit more explicit:
modelBuilder.Entity<Template>()
.HasMany(x => x.TemplateComponents)
.WithOne(x => x.Template)
.IsRequired();
modelBuilder.Entity<Compoent>()
.HasMany(x => x.TemplateComponents)
.WithOne(x => x.Component)
.IsRequired();
Or it could be wired from the TemplateComponent side.
Now you can access Template.TemplateComponents to get the collection of component references containing either the Quantity property, or multiple rows for the same component as desired. The same can be done from the Component.