C# 序列化类型为的对象时检测到循环引用。。。如何解决这个问题?
因此,我试图通过YearPlanViewModel在KendoUI MVC网格中列出员工和各自的数据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; }
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模型中有该属性。我将尝试第二个例子……:)