即使我不要求,实体框架也始终包含上下文中的数据

时间:2012-12-03 20:57:58

标签: c# entity-framework frameworks entity

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

例如,我有一个角色的用户。当我查询Users和Include Role时,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永远不会将数据加载到导航属性/集合中,除非我直接插入()它。在序列化为JSON时,我想要明确要求的内容。似乎即使延迟加载,也会加载并返回已经在上下文中的导航属性(即通常为“循环引用”)。

5 个答案:

答案 0 :(得分:20)

您所看到的行为称为 Relationship Fixup ,您无法将其停用。

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

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

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

答案 1 :(得分:1)

  

我不希望它除了我所说的内容之外还要加载任何内容。

您似乎需要使用Explicit Loading。基本上,您可以加载这样的特定实体:

context.Include("Roles")

据我所知,不应包括相关实体。确实应禁用延迟加载,您可以使用Load显式加载导航属性。

答案 2 :(得分:1)

您只能使用Select()选择所需内容。

var users = _db.Users.Select(x => new
{
    UserID = x.UserID,
    Title = x.Title,
    Email = x.Email,
    RoleID = x.RoleID
}).AsEnumerable();

答案 3 :(得分:1)

你是正确的,加上延迟加载,你会得到返回导航属性,因为序列化程序“触及”导致它们被加载。如果您希望属性返回null,则应禁用延迟加载。也就是说,“似乎”一旦实体被加载到上下文中(例如通过其他查询),它们将由序列化器处理。所以答案是告诉序列化程序不要返回导航属性。我能够找到的最好的方法是使用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));

答案 4 :(得分:-2)

首先:启用延迟加载。

第二:如果你想过滤你检索和返回的内容,那么就做一个自定义的返回对象。

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 }

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