[英]Code First - Self-referencing one to many relation
I've found a lot of similar questions here, but none of them seems to help me with my problem.我在这里发现了很多类似的问题,但似乎没有一个能帮助我解决问题。 Fluent api & attributes didn't help.流利的 api 和属性没有帮助。 The database was created, but when adding an object to it, it crashed.数据库已创建,但在向其中添加对象时,它崩溃了。 I want to have a class that has a collection of itself.我想要一个包含自身集合的类。 Here's the code I have:这是我的代码:
[Table("UObjects")]
public class UObject
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Browsable(false)]
public long ID { get; set; }
public string Name { get; set; }
[Browsable(false)]
public long? ParentID { get; set; }
public virtual UObject UParent { get; set; }
[Browsable(false)]
public virtual ICollection<UObject> UObjects { get; set; }
}
public class MyContext : DbContext
{
public DbSet<UObject> UObjects { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// This fluent API didn't help
//modelBuilder.Entity<UObject>()
// .HasOptional(u => u.UParent)
// .WithMany(u => u.UObjects)
// .HasForeignKey(u => u.ParentID);
//modelBuilder.Entity<UObject>()
// .HasOptional(u => u.UParent)
// .WithMany(u => u.UObjects)
// .Map(c =>
// {
// c.MapKey("ParentID");
// c.ToTable("UObjects");
// });
}
}
Records in database are like this:数据库中的记录是这样的:
ID | Name | ParentID
------------------------------------
1 | First | 0
2 | SubFirst | 1
3 | SubSecond | 1
4 | SubThird | 2
5 | SubFourth | 2
So how my object should look after loading the entities is next:那么接下来我的对象应该如何加载实体:
- First
- SubFirst
- SubThird
- SubFourth
- SubSecond
But every object has an empty collection.但是每个对象都有一个空集合。 What should I do to make it work properly?我应该怎么做才能使其正常工作?
You only need to mention the self reference by correcting on field rather than on navigating property like this:您只需要通过更正字段而不是像这样导航属性来提及自我引用:
[ForeignKey("UParent")] // EF need for self reference
public long? ParentID { get; set; }
And in constructor, initialize navigation properties like this:在构造函数中,像这样初始化导航属性:
public UObject()
{
// this is necessary otherwise EF will throw null object reference error. You could also put ?? operator check for a more interactive solution.
UObjects = new List<UObject>();
}
And also need to override as you were doing but like this:并且还需要像你一样重写但是像这样:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// folowwing is also necessary in case you're using identity model
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<UObjects>()
.HasOptional<UObjects>(u => u.UParent) // EF'll load Parent if any
.WithMany(u => u.UObjects); // load all childs if any
}
An entity class almost identical to yours works in EF Core.在 EF Core 中可以使用与您的实体类几乎相同的实体类。 I renamed your property ParentID
to UParentID
and added constructors.我将您的属性ParentID
重命名为UParentID
并添加了构造函数。
[Table("UObjects")]
public class UObject
{
protected UObject()
{
UObjects = new List<UObject>();
}
public UObject(UObject parent, string name)
: this()
{
Name = name;
UParent = parent;
UParent?.UObjects.Add(this);
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long ID { get; set; }
public string Name { get; set; }
public long? UParentID { get; set; }
public virtual UObject UParent { get; set; }
public virtual ICollection<UObject> UObjects { get; set; }
}
In ApplicationDBContext
I only have this:在ApplicationDBContext
我只有这个:
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<UObject>();
}
Usage (see how the properties of the root
object are filled with correct values):用法(查看root
对象的属性如何填充正确的值):
Note: I didn't bother about deletion in this code.注意:我没有在意这段代码中的删除。 If you need it, things will probably get more complicated.如果你需要它,事情可能会变得更复杂。
[ForeignKey("ParentID")] public virtual UObject? UParent { get; set; }
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.