我知道这个问题已在这里被多次提出,但它们都没有解决我的问题。
我有2个实体,StaffDTO
和Appointment
。
StaffDTO
有一个Appointment
的集合。
Appointment
具有延迟加载的导航属性。
public class StaffDTO {
public IEnumerable<Appointment> Appointments { get; set; }
}
public class Appointment {
public virtual Client Client { get; set; }
public virtual Staff Staff { get; set; }
public virtual Service Service { get; set; }
}
现在,使用LINQ,我构建了这个查询:
using (var ctx = new ApplicationDbContext())
{
var staff = ctx.Set<Staff>();
var staffs = (from stf in staff
select new StaffDTO
{
Appointments = stf.StaffAppointments
}).ToList();
}
这很有效。 但是,当我尝试序列化StaffDTO
时,我收到一条错误消息,指出已经处理了上下文。
这是有道理的,因为在序列化对象时,Appointment
集合中的每个StaffDTO.Appointments
都会读取其延迟加载的属性,但此列表的汇编上下文不存在了。
此处不能选择Appointment
类属性不是虚拟(懒惰)。
如何在LINQ查询中加载延迟属性?
我尝试了什么
我尝试使用Appointment所需的属性编写一个AppointmentDTO类并编写这个LINQ:
from stf in staff
select new StaffDTO
{
Appointments = stf.StaffAppointments.Select(a => new AppointmentDTO(a))
};
然后我得到无参数构造函数异常。
我也尝试编写一个隐式运算符来将约会转换为AppointmentDTO,但我再次从linq获得了强制转换异常。
答案 0 :(得分:0)
将其更改为Appointments = stf.StaffAppointments.ToList()
以立即实现这些对象。
答案 1 :(得分:0)
您需要ToList
stf.StaffAppointments
。 IEnumerable
中的项目是懒惰生成的,这意味着当某人尝试迭代DTO的Appointments
时,某些地方需要EF上下文处于活动状态。
除非您可以将DTO的生命周期与上下文的生命周期联系起来(这很尴尬且不必要),否则您应该在实例化DTO时从EF中提取所有数据。
编辑:我错过了您对Appointment实体中其他实体的延迟加载引用的事实。现在的问题是你的StaffDTO实际上并不是DTO。 DTO应该是特定实体中存在的所有数据的静态(优选可序列化)快照。您需要复制输出所有数据,而不仅仅是引用原始实体。您可以手动编写,也可以使用AutoMapper之类的东西来简化操作。