following official doc i setup my objects in that way but got
OneTimeSetUp: System.InvalidOperationException : The skip navigation 'Contatore.Workflow1' doesn't have a foreign key associated with it. Every skip navigation must have a configured foreign key.
for Contatori property of Workflow class
while i add foregin key correctly
public class Workflow
{
public required int Id { get; set; }
public virtual ICollection<Contatore> Contatori { get; set; } = new HashSet<Contatore>();
}
public class Contatore
{
public override int Id { get; set; }
public virtual ICollection<Contatore> ContatoriFigli { get; set; } = new HashSet<Contatore>();
public virtual ICollection<Contatore> ContatoriPadri { get; set; } = new HashSet<Contatore>();
}
internal class ContatoreConfiguration : IEntityTypeConfiguration<Contatore>
{
public void Configure(EntityTypeBuilder<Contatore> builder)
{
builder
.ToTable($"NAT_{Costanti.CodiceApplicazione}_CONTATORE_003")
.HasKey(c => c.Id)
.HasName("NAK_DASH_003");
builder.Property(b => b.Id)
.HasColumnName("ID_003")
.HasComment("Chiave primaria")
.HasDefaultValueSql($"SYUNA{Costanti.CodiceApplicazione}.SEQ_{Costanti.CodiceApplicazione}_003.NEXTVAL");
builder.HasMany(x => x.ContatoriFigli)
.WithMany(x => x.ContatoriPadri)
.UsingEntity("NAT_DASH_CONTATORE_LINKS_004",
m => m.HasOne(typeof(Contatore)).WithMany().HasForeignKey("IdContatorePrincipale").HasPrincipalKey(nameof(Contatore.Id)),
s => s.HasOne(typeof(Contatore)).WithMany().HasForeignKey("IdContatoreCollegato").HasPrincipalKey(nameof(Contatore.Id)),
j => {
j.Property("IdContatorePrincipale").HasColumnName("ID_CONT_PRINC_004");
j.Property("IdContatoreCollegato").HasColumnName("ID_CONT_COLL_004");
j.HasKey("IdContatorePrincipale", "IdContatoreCollegato");
}
);
}
internal class WorkflowConfiguration : IEntityTypeConfiguration<Workflow>
{
public void Configure(EntityTypeBuilder<Workflow> builder)
{
builder
.ToTable($"NAT_DASH_WORKFLOW_005")
.HasKey(c => c.Id)
.HasName("NAK_DASH_005");
builder.Property(b => b.Id)
.HasColumnName("ID_005")
.HasComment("Chiave primaria")
.HasDefaultValueSql($"SYUNA{Costanti.CodiceApplicazione}.SEQ_{Costanti.CodiceApplicazione}_005.NEXTVAL");
builder.HasMany(x => x.Contatori)
.WithMany()
.UsingEntity("NAT_DASH_WORKFLOW_CONTATORE_006",
m => m.HasOne(typeof(Workflow)).WithMany().HasForeignKey("ID_WORKFLOW_006").HasPrincipalKey(nameof(Workflow.Id)),
s => s.HasOne(typeof(Contatore)).WithMany().HasForeignKey("ID_CONTATORE_006").HasPrincipalKey(nameof(Contatore.Id))
);
}
Oracle table:
CREATE TABLE "NAT_DASH_WORKFLOW_CONTATORE_006"
(
"ID_WORKFLOW_006" NUMBER (9,0),
"ID_CONTATORE_006" NUMBER (9,0),
CONSTRAINT NAF_DASH_006_004 FOREIGN KEY (ID_WORKFLOW_006) REFERENCES NAT_DASH_WORKFLOW_005 (ID_005),
CONSTRAINT NAF_DASH_006_005 FOREIGN KEY (ID_CONTATORE_006) REFERENCES NAT_DASH_CONTATORE_003 (ID_003)
);
The problem is caused by the UsingEntity
configuration
builder.HasMany(x => x.Contatori)
.WithMany()
.UsingEntity("NAT_DASH_WORKFLOW_CONTATORE_006",
m => m.HasOne(typeof(Workflow)).WithMany().HasForeignKey("ID_WORKFLOW_006").HasPrincipalKey(nameof(Workflow.Id)),
s => s.HasOne(typeof(Contatore)).WithMany().HasForeignKey("ID_CONTATORE_006").HasPrincipalKey(nameof(Contatore.Id))
);
Note that in all UsingEntity
overloads expect first right relationship configuration, then left, and finally optionally the join entity itself.
In this case, the left
is Workflow
(the one on which you call HasMany
) and right is Contatore
(the one on which you call WithMany
), but your fluent configuration is the exact opposite.
So simply exchange them and the issue will be solved
builder.HasMany(x => x.Contatori)
.WithMany()
.UsingEntity("NAT_DASH_WORKFLOW_CONTATORE_006",
s => s.HasOne(typeof(Contatore)).WithMany().HasForeignKey("ID_CONTATORE_006").HasPrincipalKey(nameof(Contatore.Id)),
m => m.HasOne(typeof(Workflow)).WithMany().HasForeignKey("ID_WORKFLOW_006").HasPrincipalKey(nameof(Workflow.Id))
);
Also consider doing the same for the other many-to-many relationship shown. Because while it does not produce error, the meaning of the collection navigation properties (and their content) would be exactly the opposite of what is intended.