在ASP NET中序列化EF关系

时间:2018-11-03 12:54:54

标签: javascript c# json entity-framework

我正在尝试使用以下类在WebApi中创建一个简单的应用程序。

AuthorBookAuthor具有以下属性。

public class Author
{
    public int AuthorId{ get; set; }

    public string Name { get; set; }

    public virtual List<Book> Books { get; set; } 
}

Book具有以下属性。

public class Book
{
    public int BookId{ get; set; }

    public string Title{ get; set; }

    public virtual Author Author{ get; set; } 
}

我有一个类似这样的数据库上下文

public class DatabaseContext : DbContext
{
    public DatabaseContext() : base("dbCon")
    {
        Database.CreateIfNotExists();
        Configuration.ProxyCreationEnabled = false;
    }

    public DbSet<Author> Authors { get; set; }

    public DbSet<Books> Books { get; set; }
}

在我看来,我试图显示所有作者及其相关书籍。这是我的js代码。

function getData() {
    $.ajax({
        url: '/api/Author',
        type: 'GET',
        dataType: 'json',
        contentType: 'application/json',
        success: function (data) {
            console.log(data);
            showData(data);
        }
    });
}

function showData(data) {
    var string = '';
    $.each(data, function (i, a) {
        string += '<h1>Question title: ' + a.Name + '</h1>';
        $.each(q.Books, function (j, b) {
            string += '<p>' + b.Title + '</p><br>';
        });
    });
    $('.divclass').html(res);
}

返回所有具有相关书籍的作者的控制器方法。

public List<Author> Get()
{
    return db.Authors.Include(a => a.Books).AsNoTracking().ToList();
}

当我尝试运行项目时,我的控制台出现错误。

以下错误提示:

  

类型'System.Collections.Generic.List`1 [[WebApplication1.Models.Books,WebApplication1,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null]]'的对象图包含循环,并且如果参考跟踪已禁用。异常类型为System.Runtime.Serialization.SerializationException。

我使用代码优先迁移来播种数据库,并且我知道数据库不是空的。我该如何解决?怎么了?

2 个答案:

答案 0 :(得分:0)

错误消息告诉您,您的数据模型具有循环引用。具体来说,您的Book类具有对Author类的引用,而Author具有对Book的引用。如果您不序列化书籍的作者(您来自对象树中的作者,那么此信息就不会丢失),您可以打破循环。您可以使用ScriptIgnoreAttribute

public class Book
{
    public int BookId{ get; set; }

    public string Title{ get; set; }

    [ScriptIgnore]
    public virtual Author Author{ get; set; } 
}

另一种选择是更改JSON序列化设置,如this Q&A中所述。

答案 1 :(得分:0)

问题的一部分是实体框架的延迟加载,该延迟加载并在访问引用属性时向数据库询问数据。这对于您自己的代码很方便,但是JSON序列化 会读取每个属性。

因此,对于每个Author记录,它都会读取您已经要求的Books列表。然后,当它遍历每本书时,都会命中每本书的Author属性,并向数据库询问作者信息。然后,当它遍历该Author的属性时,它将命中Books属性,并向数据库询问该作者的所有书籍。这将永远重复一遍,但是足够聪明,只需停止并抛出该异常即可。

因此,解决此问题的另一种方法是每当您返回Entity类型时都禁用延迟加载。像这样:

public List<Author> Get()
{
    db.Configuration.LazyLoadingEnabled = false;
    return db.Authors.Include(a => a.Books).AsNoTracking().ToList();
}

这样,它仅序列化从数据库下载的已经的数据。因此,在这种情况下,当序列化每本书时,它会看到Author属性,看到它是null并继续前进。