首页 > 解决方案 > EF Core one-way self referencing entity binding

问题描述

I have set up a self referential entity using EF Core which looks like this:

Entity

public class DetailType
{
    public int DetailTypeId { get; set; }
    public string Name { get; set; }

    public int? ParentTypeId { get; set; }
    public DetailType ParentType { get; set; }
    public IEnumerable<DetailType> ChildTypes { get; set; }
}

Binding

modelBuilder.Entity<DetailType>()
    .ToTable("detailtype")
    .HasOne(x => x.ParentType)
    .WithMany(x => x.ChildTypes)
    .HasForeignKey(x => x.ParentTypeId);

I am retrieving these entities via an API and the current result looks something like this:

[
    {
        "detailTypeId": 20,
        "name": "Money",
        "parentTypeId": null,
        "parentType": null,
        "childTypes": null
    },
    {
        "detailTypeId": 22,
        "name": "Optional Extra",
        "parentTypeId": null,
        "parentType": null,
        "childTypes": [
            {
                "detailTypeId": 42,
                "name": "Extra Nights",
                "parentTypeId": 22,
                "childTypes": null
            }
        ]
    },
    {
        "detailTypeId": 42,
        "name": "Extra Nights",
        "parentTypeId": 22,
        "parentType": {
            "detailTypeId": 22,
            "name": "Optional Extra",
            "parentTypeId": null,
            "parentType": null,
            "childTypes": []
        },
        "childTypes": null
    }
]

The problem I have with this is that the third item in the array is just the reverse of the second. Is there a way to avoid this so that I only have the parent -> child relationship rather than both parent -> child as well as child -> parent. The example above is a heavily cut-down version of what my API is actually returning so I want to reduce the unnecessary bloat as much as possible because there'll be a lot of relationships going on.

Ideally what I want is to just get rid of the ParentType property but still have the ChildTypes collection but I'm not sure how to define that in the model builder.

EDIT:

I have removed the fluent relationship as it's not needed. I've also tried the following:

var roots = this.Items.Where(x => x.ParentTypeId == null);
foreach (var root in roots)
{
    root.ChildTypes = this.Items.Where(x => x.ParentTypeId == root.DetailTypeId);
}

return roots.ToList();

(this.Items is the DbSet by the way)

However this requires changing ChildTypes to an IQueryable and when I do that I get the following exception:

The type of navigation property 'ChildTypes' on the entity type 'DetailType' is 'EntityQueryable' which does not implement ICollection. Collection navigation properties must implement ICollection<> of the target type.

标签: c#entity-frameworkasp.net-coreentity-framework-coreself-referencing-table

解决方案


首先要做的事情 - 您不需要在模型构建器中指定此关系。它自己计算出来。

然后关于您的问题-我想到的第一件事(我不知道您的整个数据集)是获取所有DetailType具有ParentTypeId == null.

这样,您将获得根,然后递归地构建tree子元素。

这样做会清理你的结果,你会看到你想看到的结构。


推荐阅读