我正在尝试使用以下类在WebApi中创建一个简单的应用程序。
Author
和Book
,Author
具有以下属性。
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。
我使用代码优先迁移来播种数据库,并且我知道数据库不是空的。我该如何解决?怎么了?
答案 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
并继续前进。