23

我首先使用 MVC.NET web api、EF 和 DB,并且我在上下文中关闭了延迟加载。即使关闭了 LazyLoading,EF 也会返回太多数据。

例如,我有一个角色的用户。当我查询用户并包含角色时,Role.Users 属性会自动填充数据,因为用户已加载到上下文中。

为什么我不能让 EF 满足我的要求?还是我在这里错过了一些大事?

public partial class User
{
    public int UserID { get; set; }
    public string Title { get; set; }
    public string Email { get; set; }
    public int RoleID { get; set; }

    ....

    public virtual Role Role { get; set; }
} 

public partial class Role
{
    public int RoleID { get; set; }
    public string RoleName { get; set; }

    ....

    public virtual ICollection<User> Users { get; set; }
} 




return db.Users.Include(u => u.Role);
// ^^ user.Role.Users is filled with 1000s of users

TL;DR - 我希望 EF 永远不要将数据加载到导航属性/集合中,除非我直接 .Include() 它。序列化为 JSON 时,我只想要我明确要求的内容。似乎即使关闭延迟加载,已经在上下文中的导航属性(即通常是“循环引用”)也会被加载并返回。

4

5 回答 5

22

您看到的行为称为关系修复,您无法禁用它。

如果您正在加载具有角色的用户以对其进行序列化并将它们发送到某个地方,我猜您不想在它们已加载的上下文中跟踪实体的更改。因此,无需将它们附加到上下文和您可以使用:

return db.Users.Include(u => u.Role).AsNoTracking();

或者按照@STLRick 的建议,使用投影到专门用于序列化的对象中。

于 2012-12-03T22:15:15.287 回答
2

没错,通过延迟加载,您将返回导航属性,因为它们被序列化程序“触摸”,导致它们被加载。如果您希望属性返回为空,则应关闭延迟加载。也就是说,一旦实体被加载到上下文中(例如,通过其他查询),它们“似乎”就会被序列化程序处理。所以答案是告诉序列化器不要返回导航属性。我能找到的最好方法是使用 DTO(数据传输对象)。这使您可以准确地返回您想要的数据,而不是您的实际实体。

您的 DTO 可能如下所示:

public partial class UserDto
{
    public UserDto(user User)
    {
        UserID = user.UserID;
        Title = user.Title;
        //... and so on
    }
    public int UserID { get; set; }
    public string Title { get; set; }
    public string Email { get; set; }
    public int RoleID { get; set; }

    //exclude the Role navigation property from your DTO
}

...然后你可以做这样的事情:

return db.Users.Include(u => u.Role).Select(user => new UserDto(user));
于 2013-01-24T18:18:47.717 回答
2

您可以使用 仅选择您需要的内容Select()

var users = _db.Users.Select(x => new
{
    UserID = x.UserID,
    Title = x.Title,
    Email = x.Email,
    RoleID = x.RoleID
}).AsEnumerable();
于 2012-12-03T22:15:06.413 回答
1

除了我告诉它包含的内容之外,我不希望它加载任何内容。

看起来您需要使用Explicit Loading。基本上,您可以像这样加载特定实体:

context.Include("Roles")

据我所知,不应该包括相关实体。确实应该禁用延迟加载,您可以使用Load.

于 2012-12-03T22:00:12.350 回答
-3

首先:打开延迟加载。

第二:如果你想过滤你检索和返回的内容,然后做一个自定义的返回对象或其他东西。

from u in db.Users
join r in db.Roles
  on u.RoleID equals r.RoleID
select new { u.UserID, u.Title, u.Email, r.RoleName }

或类似的东西。您将有一个最小的返回对象,并且您的对象图将很小。

于 2012-12-03T21:58:46.643 回答