C# 实体框架总是包含上下文中的数据,即使我没有要求它

C# 实体框架总是包含上下文中的数据,即使我没有要求它,c#,entity-framework,frameworks,entity,C#,Entity Framework,Frameworks,Entity,我正在使用MVC.NET web api,EF和DB优先,并且我已经在我的上下文中关闭了延迟加载。EF返回的数据太多了,即使LazyLoading已关闭 例如,我有一个角色的用户。当我查询用户并包含角色时,Role.Users属性将自动填充数据,因为用户已加载到上下文中 为什么我不能让EF满足我的要求?还是我错过了一些重要的东西 public partial class User { public int UserID { get; set; } public string Ti

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

例如,我有一个角色的用户。当我查询用户并包含角色时,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时,我想要的正是我明确要求的。似乎即使禁用了延迟加载,也会加载并返回上下文(通常是循环引用)中已有的导航属性。

首先:启用延迟加载

第二:如果您想过滤您检索和返回的内容,那么可以执行自定义返回对象或其他操作

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 }
或者类似的。您将有一个最小的返回对象,并且您的对象图将很小

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

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

context.Include("Roles")
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));

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

您可以使用select仅选择您需要的内容


您看到的行为被调用,您无法禁用它

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

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

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

您是对的,在延迟加载的情况下,您将返回导航属性,因为它们被序列化程序触摸,从而导致加载它们。如果希望属性返回为null,则应禁用延迟加载。也就是说,似乎一旦实体通过其他查询加载到上下文中,例如,它们将由序列化程序处理。因此,答案是告诉序列化程序不要返回导航属性。我能找到的最好的方法是使用DTOs数据传输对象。这允许您准确地返回所需的数据,而不是实际的实体

您的DTO可能如下所示:

context.Include("Roles")
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));
…然后你可以这样做:

context.Include("Roles")
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));

关闭懒散加载功能后-呃,这不是迫不及待地加载吗?只是稍微抬起头。延迟加载意味着它只会在需要时加载它所需要的。。。关闭该选项与您所寻找的内容背道而驰。您可以发布代码吗?您的模型加上数据访问代码。根据我的理解和测试,延迟加载意味着当您访问作为集合的实体上的属性时,它将加载该集合。我把它关掉了,因为除了我告诉它要包含的内容之外,我不想让它加载任何东西。我的问题是,即使关闭此功能,它仍然包含已在上下文中加载的集合,因此用户只有一个角色,角色有多个用户作为导航属性,并且它已经加载了1000个用户,尽管我没有告诉EF包含它。@chris1234p不,你告诉过它不要懒惰。。。不懒惰意味着它应该一次加载所有内容,从而不必等到第一次访问集合时可能需要它时再加载。。。如果部分需求希望对象仍然附加到上下文中,因此是可更新的,那么这是一个比下面我的更好的解决方案。确保你总是包括你需要的东西;如果你这样做,我同意Serge的观点,这可能会让你更接近你想要的。你好,Serge,这就是我正在做的,但为了让它只包含我告诉它要包含的内容,我需要使用一个全新的上下文。否则,如果数据已经在上下文中,它将被加载到返回的数据中,即使我没有请求它。这就像它试图通过提供我不需要的东西来帮助我一样。出于某种原因,当我尝试AsNoTracking时,我会在序列化过程中出错。@chris1234p:可能会问一个新问题并描述这些错误。我一直在关注您的问题,如何避免实体之间的所有导航属性都被填充。如果延迟加载,您将返回导航属性,因为它们会被序列化程序触及。