懒惰和渴望加载MVC 5



我有以下代码,我尝试获取所有学生(用户类型 ID = 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
}

我既不需要课程详情,学生课程,城市也不需要用户类型

当对象序列化为 json 时,无论是否在客户端上使用它们,这些属性都是序列化的。由于序列化发生在退出 using 块之后,因此在释放上下文后访问属性。您可以执行以下三项操作之一:

使用
  1. [JsonIgnore]属性标记未使用的属性。详情请看这里

  2. 创建仅包含客户端中所需属性的第二个类,并使用SelectUser投影到这个新的更具体的对象。或者使用极光映射器自动进行映射。关于极光映射器,这可能是一篇让你入门的好文章

  3. 为每个控制器创建一个上下文,在承包商中初始化它,并且仅在替代控制器释放方法时释放它。这将确保上下文在序列化期间可用。

从性能的角度来看,2 是最好的,因为您只发送所需的内容,并且您可以更灵活地为每个操作定制输出(也许其他操作需要这些字段)。 3 是最容易实现的,但是您正在发送大量不需要的数据,并且不必要地访问数据库。 1 报价和轻松修复, 在其他人向模型添加新属性之前,您最终可能会在客户端中获得不仅不需要而且不应到达客户端的数据(密码、可能添加到模型的其他敏感信息)

提香·切尔尼科娃是完全正确的,我只想补充一件事:如果您从 WebAPI 控制器返回实体对象,则可能存在内存问题,并且您的服务器上可能存在内存泄漏,永远不要这样做

因此,一个好的做法是创建一个数据传输对象,其中包含您需要的属性,例如:

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; }
}

将实体对象强制转换为此对象并返回。

最新更新