[英]Multiple relationships to the same table in EF7(Core)
我有這樣的模特
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);
在從EF RC1
升級到RTM
之前,這種方法非常有效。 但現在它拋出: 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.
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.
如果沒有從Question
模型中刪除Variants
屬性,是否有解決此問題的方法?
萬一有人會遇到這個問題。 這是更優雅的解決方案
public class Question
{
public Guid Id { get; private set; }
public IReadOnlyList<Variant> Variants { get; private set; }
public Guid CorrectVariantId { get; private set; }
public Guid? AnsweredVariantId { get; private set; }
public bool IsAnswerCorrect => CorrectVariantId == AnsweredVariantId;
public bool IsAnswered => AnsweredVariantId != null;
}
public class Variant
{
public Guid Id { get; private set; }
public Guid QuestionId { get; private set; }
public string HiddenUserLogin { get; private set; }
public User HiddenUser { get; private set; }
}
// mapping
mb.Entity<Question>()
.HasMany(q => q.Variants)
.WithOne()
.HasForeignKey(nameof(Variant.QuestionId))
.IsRequired()
.OnDelete(DeleteBehavior.Cascade);
mb.Entity<Question>()
.HasOne(typeof(Variant))
.WithOne()
.HasForeignKey<Question>(nameof(Question.AnsweredVariantId))
.IsRequired(false)
.OnDelete(DeleteBehavior.Restrict);
// EF creates Unique Index for nullable fields
mb.Entity<Question>()
.HasIndex(q => q.AnsweredVariantId)
.IsUnique(false);
// create index instead of FK hence the cyclic dependency between Question and Variant
mb.Entity<Question>()
.HasIndex(q => q.CorrectVariantId)
.IsUnique();
這是RC1中的一個錯誤/不受歡迎的行為,它已得到修復。
你應該創建另一個屬性,比如說另一個關系的SecondQuestion。
public class Question
{
public string Id { get; set; } = Guid.NewGuid().ToString();
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; }
public Question SecondQuestion { get; set; }
}
你的DbContext:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Question>()
.HasOne(q => q.CorrectVariant)
.WithOne(v => v.SecondQuestion)
.HasForeignKey<Question>(q => q.CorrectVariantId);
modelBuilder.Entity<Variant>()
.HasOne(v => v.Question)
.WithMany(a => a.Variants).HasForeignKey(x => x.QuestionId).OnDelete(DeleteBehavior.SetNull);
base.OnModelCreating(modelBuilder);
}
如何使用它:
using (var myDb = new MyDbContext())
{
var variantFirst = new Variant();
var variantSecond = new Variant();
var question = new Question();
variantFirst.Question = question;
variantSecond.SecondQuestion = question;
myDb.Variants.Add(variantFirst);
myDb.Variants.Add(variantSecond);
myDb.SaveChanges();
}
給出的兩個例子已經讓我成為了那里的一部分,但是我想要一個集合和一個具有相同對象類型的項目,因此我的模型上的表格與原始問題中的相同。 我試圖提供一個適用於.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);
}
}
避免Navigation properties can only participate in a single relationship.
的關鍵Navigation properties can only participate in a single relationship.
錯誤是僅將導航屬性配置回父表一次。 我們使用.WithOne(t => t.ParentModel)
為ParentTable上的ChildModels
集合配置此項。 然后,我們不會通過調用.WithOne()
為后續關系配置關系的另一面,因為如果我們再次配置它(例如.WithOne(t => t.ParentModel)
),它將會出錯。
此外,導航屬性上的virtual
修飾符允許延遲加載 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.