I have such models
public class Question
{
public string Id { get; set; } = Guid.NewGuid().ToString();
public Answer Answer { get; set; }
public List<Variant> Variants { get; set; }
public string CorrectVariantId { get; set; }
public Variant CorrectVariant { get; set; }
}
public class Variant
{
public string Id { get; set; } = Guid.NewGuid().ToString();
public string QuestionId { get; set; }
public Question Question { get; set; }
}
// mapping
modelBuilder.Entity<Question>()
.HasOne(q => q.CorrectVariant)
.WithOne(v => v.Question)
.HasForeignKey<Question>(q => q.CorrectVariantId);
modelBuilder.Entity<Variant>()
.HasOne(v => v.Question)
.WithMany(a => a.Variants)
.OnDelete(DeleteBehavior.Cascade);
Which worked perfectly until I upgraded from EF RC1
to RTM
. But now it throws:
System.InvalidOperationException: Cannot create a relationship between 'Question.Variants' and 'Variant.Question', because there already is a relationship between 'Question.CorrectVariant' and 'Variant.Question'. Navigation properties can only participate in a single relationship.
Is there any workaround for this problem without just deleting Variants
property from the Question
model?
The two examples given already got me part of the way there, but I wanted a collection and a single item of the same object type and therefore the same table on my model like in the original question. I've tried to provide a simple example of this below that works for .NET Core 2.2:
public class ParentModel
{
public int Id { get; set; }
// Id for single instance navigation property
public int? ChildModelId { get; set; }
// Single instance navigation property to ChildTable, identified by ChildModelId property as foreign key
public virtual ChildModel ChildModel { get; set; }
// Collection navigation property to ChildTable with identified by ParentId property
public virtual ICollection<ChildModel> ChildModels { get; set; }
}
public class ChildModel
{
public int Id { get; set; }
// Id for ParentModel property back to ParentTable
public int ParentId { get; set; }
// Single instance navigation property to ParentTable, identified by ParentId property as foreign key
public virtual ParentModel ParentModel { get; set; }
}
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<ParentModel>()
.ToTable("ParentTable");
// Configure collection of ChildModels (ParentTable to ChildTable/one-to-many relationship)
builder.Entity<ParentModel>()
.HasMany(t => t.ChildModels)
.WithOne(t => t.ParentModel)
.HasForeignKey(t => t.ParentId)
.IsRequired()
.OnDelete(DeleteBehavior.Cascade);
builder.Entity<ChildModel>()
.ToTable("ChildTable");
// Configure single ChildModel navigation property on ParentModel (one-to-one relationship)
builder.Entity<ParentModel>()
.HasOne(t => t.ChildModel)
.WithOne()
.HasForeignKey(typeof(ParentModel), nameof(ParentModel.ChildModelId))
.IsRequired(false)
.OnDelete(DeleteBehavior.Restrict);
}
}
The key to avoiding the Navigation properties can only participate in a single relationship.
error is to configure the navigation property back to the parent table only once. We configure this on for the ChildModels
collection on the ParentTable using .WithOne(t => t.ParentModel)
. We then don't bother configuring the other side of the relationship for the subsequent relationships by calling .WithOne()
empty, because if we did configure it again (eg .WithOne(t => t.ParentModel)
) it would error.
Also the virtual
modifiers on the navigation properties are to allow for lazy loading.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With