惰性和急切加载 MVC 5

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 块之后,因此在释放上下文后访问属性。您可以执行以下三项操作之一:

  1. [JsonIgnore]属性标记未使用的属性。详情见here

  2. 创建第二个 class,它只包含您在客户端中需要的属性,并使用 SelectUser 投影到这个新的更具体的对象。或者使用 auromapper 自动进行映射。关于 auromapper this 可能是一篇帮助您入门的好文章

  3. 为每个控制器创建一个上下文,在承包商中对其进行初始化,并且仅将其置于对控制器处置方法的重写中。这将确保上下文在序列化期间可用。

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

Titian Cernicova 完全正确,我只想补充一件事:如果你 return 来自 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; }
}

将您的实体对象投射到此和 return。