[英]Lazy & eager Loading MVC 5
我有以下代码,我尝试让所有学生(UserTypeID = 2)
using SchoolData;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
namespace SchoolAPI.Controllers
{
public class StudentsController : ApiController
{
public List<User> Get()
{
using(SchoolEntities DB = new SchoolEntities())
{
var L = DB.Users.Where(u => u.UserTypeID == 2).ToList();
return L;
}
}
public User Get(int id)
{
using(SchoolEntities DB = new SchoolEntities())
{
return DB.Users.Where(u => u.UserTypeID == 2).FirstOrDefault(u => u.UID == id);
}
}
}
}
当我在启用延迟加载的情况下运行此代码时,我尝试通过功能Get()吸引所有学生,这将引发错误:
"Message": "An error has occurred.",
"ExceptionMessage": "The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'.",
"ExceptionType": "System.InvalidOperationException",
"StackTrace": null,
"InnerException": {
"Message": "An error has occurred.",
"ExceptionMessage": "Error getting value from 'City' on 'System.Data.Entity.DynamicProxies.User_43D4A249734A75DBA5AC314F4FE462E834BDC252CC9384BF940FE65C74CE3D08'
和
"The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
当我尝试禁用惰性模式并重新运行时,它会正确获取对象,但带有一些其他不需要的参数,如下所示:
{
"City": null,
"CourseDetails": [],
"StudentsCourses": [],
"UserType": null,
"UID": 2,
"FName": "Ahmed",
"LName": "Mano",
"Birthdate": "1995-05-27T00:00:00",
"CityID": 1,
"UserTypeID": 2
}
而且我既不需要CourseDetails,StudentsCourses,City或UserType
当对象序列化为json时,无论是否在客户端上使用它们,这些属性都会被序列化。 由于序列化是在您退出using块之后发生的,因此在处理上下文之后可以访问属性。 您可以做以下三件事之一:
使用[JsonIgnore]
属性标记未使用的属性。 详情请看这里
创建仅包含客户端中所需属性的第二个类,然后使用Select
将User
投影到该新的更特定的对象。 或使用auromapper自动进行映射。 关于auromapper, 这可能是一篇入门的好文章
为每个控制器创建一个上下文,在承包商中对其进行初始化,然后仅以对控制器dispose方法的替代方式对其进行处理。 这将确保上下文在序列化期间可用。
从性能的角度来看,2是最好的选择,因为您只发送所需的信息,并且可以灵活地将输出调整为每个操作(也许其他操作需要这些字段)。 3是最简单的实现,但是您将发送大量不需要的数据,并不必要地访问数据库。 1提供并且易于修复,直到其他人向模型添加新属性,而且,您最终可能会在客户端中得到不仅不需要的数据,而且这些数据不应到达客户端(密码,其他敏感信息)可能会添加到模型中)
Titian Cernicova完全正确,我只想添加一件事:如果您从WebAPI控制器返回了一个Entity Object,您可能会遇到内存问题,并且可能在服务器上发生内存泄漏, 请不要这样做
因此,一个好的做法是创建一个具有所需属性的数据传输对象,例如:
public class DtoUser
{
public int UID { get; set; }
public string FName { get; set; }
public DateTime Birthdate { get; set; }
public int CityID { get; set; }
public int UserTypeID { get; set; }
}
将您的实体对象转换为此对象并返回。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.