Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 序列化类型为的对象时检测到循环引用。。。如何解决这个问题?_C#_Linq - Fatal编程技术网

C# 序列化类型为的对象时检测到循环引用。。。如何解决这个问题?

C# 序列化类型为的对象时检测到循环引用。。。如何解决这个问题?,c#,linq,C#,Linq,因此,我试图通过YearPlanViewModel在KendoUI MVC网格中列出员工和各自的数据 List<Business.Employee> a = wtmEntities.Employee.Include(e => e.CompensationDayRequests).ToList(); 这就是模型 public class YearPlanViewModel { public int? ID { get; set; }

因此,我试图通过YearPlanViewModel在KendoUI MVC网格中列出员工和各自的数据

 List<Business.Employee> a = wtmEntities.Employee.Include(e => e.CompensationDayRequests).ToList();
这就是模型

 public class YearPlanViewModel
    {
        public int? ID { get; set; }
        public  String EmployeeName { get; set; }
        public List<Business.CompensationDayRequest> CompensationDays { get; set; }
        public List<Business.EmployeeVacationDay> VacationDays { get; set; }
        public List<Business.Displacement> Displacementes { get; set; }
        public List<Business.CriticalTask> CriticalTasks { get; set; }
        public List<Tuple<Business.Absence,Business.TimePeriod>> Absences {get;set;}


    }
公共类YearPlanViewModel
{
公共int?ID{get;set;}
公共字符串EmployeeName{get;set;}
公共列表补偿天数{get;set;}
公共列表假期天数{get;set;}
公共列表置换{get;set;}
公共列表关键任务{get;set;}
公共列表缺失{get;set;}
}
因此,对于网格的DataSource函数,这是我的查询

List<YearPlanViewModel> a = wtmEntities.Employee.ToList().Select(employee => new YearPlanViewModel
        {
            ID = employee.IDEmployee,
            EmployeeName = employee.FirstName + " " + employee.LastName,
            CompensationDays = employee.CompensationDayRequests.Where(cr => cr.Employee.IDEmployee == employee.IDEmployee && cr.Date.Year == 2015).ToList(),
            VacationDays = employee.EmployeeVacationDays.Where(vc => vc.Employee.IDEmployee == employee.IDEmployee && vc.Day.Year == 2014).ToList()
            ,
            Displacementes = employee.Displacements.Where(d => d.Employee.IDEmployee == employee.IDEmployee && d.StartDate.Year == 2014).ToList(),

            Absences = employee.Absences.Join(wtmEntities.TimePeriods,
            abs => abs.Period,
             tps => tps.IDTimePeriod,
             (abs, tps) => new { abs, tps })
             .Where(x => x.abs.Employee.IDEmployee == employee.IDEmployee)
             .ToList()
             .Select(t => new Tuple<Business.Absence, Business.TimePeriod>(t.abs, t.tps)).ToList()
             ,

            CriticalTasks = wtmEntities.CriticalTasks.Where(ct => ct.IDPerson == employee.IDPerson).ToList()

        }).ToList();
List a=wtmEntities.Employee.ToList().Select(Employee=>new YearPlanViewModel
{
ID=employee.ideemployee,
EmployeeName=employee.FirstName+“”+employee.LastName,
CompensationDays=employee.CompensationDayRequests.Where(cr=>cr.employee.IdeEmployee==employee.IdeEmployee&&cr.Date.Year==2015)。ToList(),
休假天数=employee.EmployeeVacationDays.Where(vc=>vc.employee.ideemployee==employee.ideemployee&&vc.Day.Year==2014)。ToList()
,
置换=employee.Displacements.Where(d=>d.employee.ideemployee==employee.ideemployee&&d.StartDate.Year==2014)。ToList(),
缺勤=员工.缺勤.加入(wtmEntities.TimePeriods,
abs=>abs.期间,
tps=>tps.IDTimePeriod,
(abs,tps)=>新的{abs,tps})
.其中(x=>x.abs.Employee.ideemployee==Employee.ideemployee)
托利斯先生()
.Select(t=>newtuple(t.abs,t.tps)).ToList()
,
CriticalTasks=wtmenties.CriticalTasks.Where(ct=>ct.IDPerson==employee.IDPerson.ToList())
}).ToList();
但是我得到了标题上说的错误,基本上是因为补偿日、位移等都与员工有关,这就是为什么有循环引用的原因

但是,他们告诉我应该在查询中使用include,这样就不会发生这种情况,所以我尝试使用CompensationDays,并使用Employee类而不是ViewModel

 List<Business.Employee> a = wtmEntities.Employee.Include(e => e.CompensationDayRequests).ToList();
List a=wtmEntities.Employee.Include(e=>e.compensationdaysrequests.ToList();
循环引用问题仍在继续,我不知道该如何更改查询以避免再次发生。不管谁帮忙,谢谢。:)

工作=>重构(让它工作,然后重构)

工作:主要问题是试图在一次行动中做太多。当您使用LINQ时,操作被推迟到请求运行时,因此编译器无法捕获问题(在本例中无论如何都不会)

解决这个问题的一种方法是首先获取父查询的信息(看起来像这里的雇员)。然后,您可以提取其他查询所需的信息,从而构建层次结构

这将在将信息编入列表方面做更多的工作,但将避免循环引用

重构:一旦你让它工作起来,然后重构使它更容易理解和简洁。您可能会发现,一旦提取出将递归的部分,就可以通过一个查询构建列表


注意:我希望我有一个“just do this”的答案,但是我没有时间仔细阅读所有的代码,看看是否有一个特定的部分可以解决递归问题。

我通常使用两种方法来解决这个问题,它们都专注于序列化点,而不是模型结构本身。(因为模型在服务器端代码中很好,而且只是序列化,这会导致问题。)

首先,让我们简化一个更人为的例子来说明。大概是这样的:

public class Parent
{
    public virtual ICollection<Child> Children { get; set; }
}

public class Child
{
    public virtual Parent Parent { get; set; }
}
var someParent = SomeOperationToGetAParent();
return new ParentViewModel
{
    Children = someParent.Children.Select(c => new ChildViewModel())
};
在服务器端代码中,它从来不会有什么区别,但在API边界处序列化时,它根本不包含该属性。客户端代码不需要它

如果它不是普遍正确的,并且只有这一个操作需要忽略子对象,那么在序列化之前,您可以将模型转换为自定义视图模型。这是一个多一点的手动,可能会导致更多的重复结构,但它可以在紧要关头完成工作。它可能看起来像这样:

public class Parent
{
    public virtual ICollection<Child> Children { get; set; }
}

public class Child
{
    public virtual Parent Parent { get; set; }
}
var someParent = SomeOperationToGetAParent();
return new ParentViewModel
{
    Children = someParent.Children.Select(c => new ChildViewModel())
};
在这个人为设计的示例中,没有任何其他属性可供使用,但在更现实的情况下会有。您甚至可以将该构造重构为视图模型本身,添加工厂方法,在给定模型实例的情况下生成视图模型实例。比如:

public class ParentViewModel
{
    public IEnumerable<ChildViewModel> Children { get; set; }
    // other properties

    public static ParentViewModel BuildViewModel(Parent parent)
    {
        return new ParentViewModel
        {
            Children = parent.Children.Select(c => ChildViewModel.BuildViewModel(c)),
            // other properties
        };
    }
}

public class ChildViewModel
{
    // other properties

    public static ChildViewModel BuildViewModel(Child child)
    {
        return new ChildViewModel
        {
            // other properties
        };
    }
}
公共类ParentViewModel
{
公共IEnumerable子项{get;set;}
//其他属性
公共静态父视图模型BuildViewModel(父-父)
{
返回新的ParentViewModel
{
Children=parent.Children.Select(c=>ChildViewModel.BuildViewModel(c)),
//其他属性
};
}
}
公共类ChildViewModel
{
//其他属性
公共静态子视图模型BuildViewModel(子-子)
{
返回新的ChildViewModel
{
//其他属性
};
}
}
这可能会涉及到很多问题。代码本身非常简单,但对于大型复杂模型结构,可能会有很多代码。这就产生了使用
JsonIgnore
替代的实际吸引力


导航属性在服务器端代码中非常有用(在实体框架中通常是必需的),但它们对序列化程序没有多大意义。

在子类中,我没有指向父类的属性,但在实体框架的DB模型中有该属性。我将尝试第二个例子……:)