我有一个对象,可以选择引用下一个和/或前一个记录。像这样:
public class Foo
{
[Key]
public int Id {get; set;}
[ForeignKey("Previous")]
public int? PreviousId {get; set;}
public Foo Previous {get; set;}
[InverseProperty("Previous")]
public Foo Next {get; set;}
}
不幸的是,这不起作用,而是导致错误消息Unable to determine the principal end of an association between the types Foo and Foo
。
我们的想法是,通过设置PreviousId
,上一个Foo
将自动由EF设置Next
。这是为了防止Next
和Previous
导致错误导致的错误。另请注意,PreviousId
可以是null
,在这种情况下,数据库中的任何记录都不应该有Next
指向该记录。有没有办法实现这个?
答案 0 :(得分:7)
我通过流畅的api aproach成功实现了你想要的目标。我需要从Foo类中删除PreiousId属性 - 稍后将通过映射添加它。
public class Foo
{
[Key]
public virtual int Id { get; set; }
public virtual Foo Previous { get; set; }
public virtual Foo Next { get; set; }
}
将所有属性更改为虚拟,因为这将允许ef动态跟踪内存中属性的状态。然后在DbContext派生类中,你需要覆盖OnModelCreating方法并在那里定义映射:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Foo>()
.HasOptional(f => f.Next)
.WithOptionalPrincipal(f => f.Previous)
.Map(c => c.MapKey("PreviousId"));
base.OnModelCreating(modelBuilder);
}
这将添加到Foo表的PreviousId列,它将成为关系的外键。它将定义1-0的关系。如果将一个Foo实体分配给另一个属性,则分配的实体将在Next属性中引用它。我用以下代码测试了它:
using(MyDbContext context = new MyDbContext("Test"))
{
context.Database.Delete();
Foo foo1 = context.Foos.Create();
Foo foo2 = context.Foos.Create();
foo1.Next = foo2;
context.Foos.Add(foo1);
context.Foos.Add(foo2);
context.SaveChanges();
}
using (MyDbContext context = new MyDbContext("Test"))
{
Foo foo1 = context.Foos.OrderBy(f => f.Id).First();
Foo foo2 = context.Foos.OrderBy(f => f.Id).Skip(1).First();
// foo1.Next == foo2 and foo2.Previous == foo1
}
答案 1 :(得分:1)
对于那些使用实体框架核心的人来说,这就是我最后做的事情
public class LinkedListNode
{
public int Id { get; set; }
public int? NextId { get; set; }
public virtual LinkedListNode Next { get; set; }
public int? PrevId { get; set; }
public virtual LinkedListNode Prev { get; set; }
public long SortOrder { get; set; }
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<LinkedListNode>()
.HasOne<LinkedListNode>(x => x.Next)
.WithMany()
.HasPrincipalKey("Id")
.HasForeignKey("NextId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired(false);
builder.Entity<LinkedListNode>()
.HasOne<LinkedListNode>(x => x.Prev)
.WithMany()
.HasPrincipalKey("Id")
.HasForeignKey("PrevId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired(false);
}