查询列子集

时间:2018-04-20 02:01:30

标签: c# sql-server entity-framework entity-framework-core

来自文档:

  

Entity Framework Core会自动将导航属性修复到先前加载到上下文实例中的任何其他实体。因此,即使您没有明确包含导航属性的数据,如果之前加载了部分或全部相关实体,仍可能会填充该属性。

实体设置:

public class Page{

    public Page () {
        Event = new HashSet<Event>();
    }

    [Key]
    public int Id { get; set; }
    public string Title { get; set; }
    public string Content { get; set; } // don't want to retrieve, too large

    public ICollection<Event> Event { get; set; }
}

public class Event{

    [Key]
    public int Id { get; set; }
    public string Name { get; set; }
    public string Type { get; set; }

    public Page Page { get; set; }
}

上下文设置为一对多关系。

这些是我一个接一个地运行的查询:

var pages = _dbContext.Page.Select(page => new Page
        {
            Id = page.Id,
            Title = page.Title
        }).ToList();

var events = _dbContent.Event.ToList();

我希望每个Page都填充Events个集合(反之亦然Event Page引用,但修复不会发生(Page中的Eventnull,而Event中的Pagenull

如果我用这个替换第一个查询,则修复工作正常:

var pages = _dbContext.Page.ToList();

所以看来,通过投影,修复工作不会发生。我在2个查询中将其拆分的原因是为了避免使用类似Include的内容,这会产生巨大的连接并重复大量数据。

有什么方法吗?我是否需要自己手动修复?

2 个答案:

答案 0 :(得分:3)

当您在查询中自己投射到新类型时,EF Core不会跟踪查询中出现的对象,即使它们是属于Model的实体类型。这是设计的。

由于在您的情况下Page未被跟踪,Events无需修复。因此,您将看到空导航属性。

此行为与先前版本(EF6)相同。不跟踪的主要原因是,在您的情况下,您正在创建新的Page而不加载Content。如果我们跟踪新实体,那么它将Content设置为null(默认(字符串))。如果您将整个实体标记为已修改,则SaveChanges将最终在数据库的Content列中保存空值。这会导致数据丢失。由于较小的错误可能导致数据丢失等重大问题,因此默认情况下EF Core不会跟踪实体。另一个原因是弱实体类型(或EF6中的复杂类型)与其他实体共享CLR类型但通过Parent类型唯一标识,如果您突出显示这样的实体,那么EF Core无法找出没有父实体的实体类型信息。

您可以通过调用Attach方法将这些实体放在changetracker中,这将导致修复,您将获得所需的行为。小心不要保存它们。

通常,您想要的方案很有用。 This issue正在跟踪对EF Core中的支持。

答案 1 :(得分:0)

我认为这不应该奏效。您是否验证了以前版本的EntityFramework中的此行为?因为,您不是要提取完整实体,只提取它的属性,然后将其传递给新实体,您实际上只是选择属性并创建新实体。

如果您想要附加此选项,您可以在选择页面后手动调用附加方法

var pages = _dbContext.Page.Select(page => new Page
    {
        Id = page.Id,
        Title = page.Title
    }).ToList();

pages.ForEach(p => _dbContext.Page.Attach(p));

请记住,如果您调用SaveChanges之后您将丢失已卸载的属性,因此仅在调用Get方法时使用此方法