使用实体框架或自动映射器处理循环引用

Handle circular reference with entity framework or automapper

提问人:Simon 提问时间:11/17/2023 最后编辑:Simon 更新时间:11/20/2023 访问量:57

问:

我正在尝试学习和了解如何使用实体框架和自动映射器与关系。 更具体地说,maby 是循环引用。

假设我有 3 个对象:

public class Author
{
    public string id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public IEnumerable<Book>? Books { get; set; }
}
public class Book
{
    public string id { get; set; }
    public string Name { get; set; }

    public Author Author { get; set; }
    public IEnumerable<Page>? Pages { get; set; }
}
public class Page
{
    public string id { get; set; }
    public string Text { get; set; }

    public Book Book { get; set; }
    public Author Author { get; set; }
}

在获取作者时,我希望我的回复是这样的:

{
    "id": "author1",
    "firstName": "famous",
    "lastName": "author",
    "books": [
        {
            "id": "book1",
            "name": "famousBookName",
            "pages": [
                {
                    "id": "page1",
                    "text": "..."
                },
                {
                    "id": "page2",
                    "text": "..."
                }
            ]
        }
    ]
}

但是当拿一本书时,我想要这样的回应:

{
    "id": "book1",
    "name": "famousBookName",
    "author": {
        "id": "author1",
        "firstName": "famous",
        "lastName": "author"
    },
    "pages": [
        {
            "id": "page1",
            "text": "..."
        },
        {
            "id": "page2",
            "text": "..."
        }
    ]
}

在获取页面时,我想要这样的响应:

{
    "id": "page1",
    "text": "...",
    "book": {
        "id": "book1",
        "name": "famousBookName"
    },
    "author": {
        "id": "author1",
        "firstName": "famous",
        "lastName": "author"
    }
}

但是,我最终得到的是这样的:

{
    "id": "author1",
    "firstName": "famous",
    "lastName": "author",
    "books": [
        {
            "id": "book1",
            "name": "famousBookName",
            "pages": [
                {
                    "id": "page1",
                    "text": "...",
                    "book": {
                        "id": "book1",
                        "name": "famousBookName",
                        "author": {
                            "id": "author1",
                            "firstName": "famous",
                            "lastName": "author",
                            "books": [...]
                        },
                        "pages": [...]
                    },
                    "author": {
                        "id": "author1",
                        "firstName": "famous",
                        "lastName": "author",
                        "books": [...]
                    }
                }
            ]
        }
    ]
}

有没有办法解决这个问题?要么告诉 EntityFramework 跳过填充循环引用,要么通过 AutoMapper 设置?

还是添加我映射到的多个 DTO 的唯一方法? 一个是有书的作者,一个是没有书的作者 一个用于没有作者和页面的书籍,一个用于有作者和页面的书籍 一个用于不带书籍和作者的页面,另一个用于带有页面和作者的书籍

我觉得随着项目的发展,这样做最终会得到绝对的大量课程

解决方案可能是使用 .select() 并简单地手动映射对象,甚至可能将其映射到异常类型。但这是好的做法吗?

C# Entity-Framework-Core Automapper Net-7.0

评论

0赞 JonasH 11/17/2023
这将是我所期望的行为。如果不想包含循环引用,请删除 Pages.Book-property 。您还可以考虑将 EF 实体与 Web 服务器或其他类型的导出中使用的类型分开,另外,您的错别字是不是?它不包括在预期输出中。Book.Book
0赞 Simon 11/17/2023
对不起,是的,Book.Book 是一个错别字,它应该是对作者的引用。这里的课程是为了解释这个问题,而没有我的精算课程的所有额外开销。问题在于,消费者在获取特定页面时需要有关相关书籍和作者的信息。我正在将其映射到 DTO 中,但这保留了引用。
0赞 JonasH 11/17/2023
如果您查询一本书并包含作者,则该 author.books 应始终包含您查询的书籍。但是,根据您编写查询的方式,它可能包括也可能不包括作者的所有书籍。我不确定您是如何进行映射的,但映射不应该包含所有引用。
0赞 Guru Stron 11/17/2023
为什么要“解决”这个问题?
0赞 Guru Stron 11/17/2023
对于 ASP.NET Core - 还要检查这个

答:

0赞 Ron 11/17/2023 #1

您想要的是配置 json 序列化程序,使其不遵循循环引用。

为此,您可以为所有项目配置服务,并在 program.cs 中添加该行

builder.Services.AddControllers().AddJsonOptions(options =>
{
    options.JsonSerializerOptions.ReferenceHandler = System.Text.Json.Serialization.ReferenceHandler.IgnoreCycles;
});

您还可以根据请求执行此操作,在请求中将配置添加到 json 序列化程序:

 var serializerSettings = new JsonSerializerOptions
 {

         DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.Never,
         MaxDepth = 1

 };

 var jsonContent = JsonSerializer.Serialize(author);

然后,您可以从控制器发送 json 内容

0赞 Simon 11/20/2023 #2

事实证明,遮阳篷相当简单,只需添加:

.PreserveReferences()

到自动映射器映射配置文件。