【问题标题】:A circular reference was detected while serializing an object + ASP.net mvc5 + Entity Framework [duplicate]序列化对象+ ASP.net mvc5 + Entity Framework时检测到循环引用[重复]
【发布时间】:2017-10-05 17:25:20
【问题描述】:

我正在使用 ASP.Net MVC 5、带有 SQL Server 的实体框架开发一个测试应用程序。

在我的场景中,数据库中有 2 个表。 StudentQualification。 一名学生拥有一项或多项资格。

我需要通过提供 studentID 从数据库中获取student,并且Student(导航属性)的Qualification 列表应该包含他或她拥有的所有资格。

我实现的控制器方法如下。

        public JsonResult getStudentInfo(int studentId)
    {
        db.Configuration.ProxyCreationEnabled = false;
        Student ss = (Student) (from s in db.Students where s.Id == studentId select s).FirstOrDefault();
        ss.Qualifications = (from q in db.Qualifications where q.StudentId == ss.Id select q).ToList();
        return Json(ss, JsonRequestBehavior.AllowGet);
    }

但是当我试图调用这个函数时,它会显示这个错误。

A circular reference was detected while serializing an object of type 'App1.Models.Student'.

如何解决此问题。 我需要通过Student 实例的完整资格列表。

我的学生模型类如下

    public partial class Student
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public Student()
    {
        this.Qualifications = new HashSet<Qualification>();
    }

    public int Id { get; set; }
    public string Name { get; set; }
    public Nullable<int> Age { get; set; }
    public Nullable<byte> Gender { get; set; }
    public string City { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<Qualification> Qualifications { get; set; }
}

我的QualificationModel类如下

    public partial class Qualification
{
    public int Id { get; set; }
    public Nullable<int> StudentId { get; set; }
    public string QualificationName { get; set; }
    public string Institute { get; set; }
    public Nullable<System.DateTime> EffectiveDate { get; set; }

    public virtual Student Student { get; set; }
}

上面的模型类是使用实体数据模型生成的。 我遵循数据库优先方法..

提前致谢。

【问题讨论】:

  • Qualification 类是什么样的?
  • @Robert 对不起。我刚刚更新了问题。
  • 是的……我猜罗伯特猜对了;学生->资格->学生。是您的循环参考。过去,我编写代码将 Student.Qualification.Student 设置为 null,这样就不会发生这种情况。我确信有更好的解决方案。我不知道它是否能解决这个问题,但你可以试试这个库:github.com/zzzprojects/GraphDiff
  • 我认为您可能不需要虚拟学生资格认证,尽管我可能是错的。如果您需要获取父学生,可以(从 db.Students 中的 s.Id ==qualification.StudentId select s).FirstOrDefault();或类似的
  • 或者只是创建一个 public Student { get { return Student.GetById(this.StudentId); }} 或类似的东西

标签: c# asp.net asp.net-mvc entity-framework asp.net-mvc-4


【解决方案1】:

几件事:

  1. 我使用可空位作为来自Student 类的性别类型,而不是byte
  2. 你说一个学生有一个或多个资格,但你没有提到相同的资格可以在不同的学生之间共享。如果,那么您需要第三张表StudentQualification 来存储多对多配置。 否则,您的两个表设置很好,但我仍然不会将Qualification 表中的StudentId 设置为可空,因为没有学生,资格就不算什么。一个学生有一个或多个资格,那么一个资格必须有一个学生,如果你反过来想的话。

这是由 Microsoft Entity Framework 生成的代码。

学生

namespace DL.SO.StudentQualification.Data
{
    using System;
    using System.Collections.Generic;

    public partial class Student
    {
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
        public Student()
        {
            this.Qualifications = new HashSet<Qualification>();
        }

        public int Id { get; set; }
        public string Name { get; set; }
        public Nullable<int> Age { get; set; }
        public Nullable<bool> Gender { get; set; }
        public string City { get; set; }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<Qualification> Qualifications { get; set; }
    }
}

资格

namespace DL.SO.StudentQualification.Data
{
    using System;
    using System.Collections.Generic;

    public partial class Qualification
    {
        public int Id { get; set; }
        public int StudentId { get; set; }
        public string QualificationName { get; set; }
        public string Institute { get; set; }
        public Nullable<System.DateTime> EffectiveDate { get; set; }

        public virtual Student Student { get; set; }
    }
}

这是获取学生的Controller方法的代码。

    public JsonResult GetStudentInfo(int studentId)
    {
        using (var db = new AppDbContext())
        {
            // Method syntax
            var student = db.Students
                .SingleOrDefault(x => x.Id == studentId);

            // Query syntax
            //var student =
            //    from s in db.Students
            //    where s.Id == studentId
            //    select s;

            return Json(student, JsonRequestBehavior.AllowGet);
        }
    }

您无需单独查找学生及其资格(否则为什么您会使用 EF),因为 EF 的导航属性可以帮助您。我认为这就是您的错误的来源。

如果您选择student.Qualifications,那么您将获得该学生的资格列表。

其他建议:

  1. 永远不要直接将数据库模型返回到页面,即返回到视图或作为 Json 对象返回,因为您不想公开不想公开的属性。使用ViewModel 定义您真正想要公开的属性并将数据传输到视图模型。而是返回视图模型。
  2. 您可以考虑使用存储库模式并将DbContext 注入存储库。那里有大量的材料。您可以通过 Google 搜索和学习。

【讨论】:

    猜你喜欢
    • 2015-09-09
    • 1970-01-01
    • 2012-05-04
    • 2012-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-26
    相关资源
    最近更新 更多