Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
How to refer to the same class twice from one Entity Framework entity?
I have two classes, Contestant and Picture, with the following setup:
public class Contestant
{
...
public int AvatarID { get; set; }
[ForeignKey(nameof(AvatarID))]
public virtual Picture? Avatar { get; set; }
public virtual ICollection<Picture>? Pictures { get; set; }
...
}
public class Picture
{
...
public int ContestantID { get; set; }
[ForeignKey(nameof(ContestantID))]
public virtual Contestant? Contestant { get; set; }
...
}
Each contestant instance has a set of pictures and a single picture from the set that serves as their avatar.
The original setup (without AvatarID or Avatar relationship) worked fine. After adding the Avatar field and relationship, I get a run-time error message when I try to load either the Contestant set or Picture set. It reads:
System.InvalidOperationException: 'Unable to determine the relationship represented by navigation 'Contestant.Avatar' of type 'Picture.' Either manually configure the relationship, or ignore this property using the '[NotMapper]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.'
From my research, this happens when a class refers to another class twice. The answers I saw all involved the same class having both keys of the relationship. For example, a Project class might have multiple employees assigned, one as ProjectEngineer the other as AssignedDeveloper. For those, defining the [ForeignKey()] in the same file worked. I do not know what I need to do, here or possibly in the DbContext's OnModelCreating method.
1 answer
The following users marked this post as Works for me:
User | Comment | Date |
---|---|---|
FrankLuke | (no comment) | Oct 13, 2022 at 03:17 |
I tried to replicate your case and the only workable solution I could find is to use OnModelCreating configuration (fluent style) instead of attributes:
public class Contestant
{
public int Id { get; set; }
public int AvatarID { get; set; }
public virtual Picture? Avatar { get; set; }
public virtual ICollection<Picture>? Pictures { get; set; }
}
public class Picture
{
public int Id { get; set; }
public int ContestantID { get; set; }
public virtual Contestant? Contestant { get; set; }
public virtual Contestant? ContestantInverse { get; set; }
}
modelBuilder.Entity<Contestant>()
.HasOne(u => u.Avatar)
.WithOne(r => r.Contestant)
.HasForeignKey<Contestant>(u => u.AvatarID)
.HasConstraintName("FK_Contestant_Avatar")
.OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<Picture>()
.HasOne(d => d.ContestantInverse)
.WithMany(p => p.Pictures)
.HasConstraintName("FK_Picture_Contestant")
.OnDelete(DeleteBehavior.Restrict);
The Picture
needs two navigation properties related to Contestant
since it has two relations with it (1:1 and n:1).
As a side note, while liking the attributes more, I decided to use the fluent syntax only because some configurations are not supported by the attributes (e.g. index on 2+ properties), and having the configuration split in two can lead to confusion.
0 comment threads