查询列子集时的EF Core修复 [英] EF Core fix-up when querying subset of columns

查看:123
本文介绍了查询列子集时的EF Core修复的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

从文档中:


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


实体设置:

 公共类页面{

公共页面() {
Event = new HashSet< Event>();
}

[Key]
public int Id {get;组; }
公用字串Title {get;组; }
公共字符串Content {get;组; } //不想检索太大的

public ICollection< Event>事件{get;组; }
}

public class Event {

[Key]
public int Id {get;组; }
公共字符串Name {get;组; }
公共字符串类型{get;组; }

公开页面Page {组; }
}

上下文是通过一对多关系设置的。 / p>

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

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

var events = _dbContent.Event.ToList();

我希望每个页面都有<填充了code> Events 集合(反之亦然,对于 Event Page 参考),但修复没有发生(事件中的页面 null 页面中的事件)。



如果我以此替换第一个查询,则解决方法有效:

  var pages = _dbContext.Page.ToList(); 

因此,似乎无法进行修正。我之所以将其分为2个查询,是为了避免使用类似 Include 之类的东西,它们会产生巨大的联接并复制大量数据。



有什么解决办法吗?我需要自己亲自进行修复吗?

解决方案

当您自己在查询中将新类型投影到项目时,EF Core不会跟踪来自查询的对象,即使它们属于Model实体的类型也是如此。



由于在您的情况下,页面没有被跟踪,因此事件与修复无关。因此,您将看到空的导航属性。



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



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



通常,所需的方案很有用。 此问题正在跟踪对EF Core中的支持。


From the documentation:

Entity Framework Core will automatically fix-up navigation properties to any other entities that were previously loaded into the context instance. So even if you don't explicitly include the data for a navigation property, the property may still be populated if some or all of the related entities were previously loaded.

Entities setup:

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; }
}

The context is set up with a One-To-Many relationship.

These are the queries I run, one after the other:

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

var events = _dbContent.Event.ToList();

I expect each Page to have the Events collection populated (and vice-versa for Event with the Page reference), but the fix-up doesn't happen (Page in Event is null, and Event in Page is null).

If I replace the first query by this, then the fix-up works:

var pages = _dbContext.Page.ToList();

So it seems that with projection the fix-up doesn't happen. The reason I split this in 2 queries was to avoid using something like Include which would make a huge join and duplicate plenty of data.

Is there any way around that? Do I need to do the fix-up manually myself?

解决方案

When you project into a new type yourself in the query, EF Core does not track the object coming out of the query even if they are of type an entity which is part of Model. This is by design.

Since in your case Pages are not getting tracked, Events have nothing to do fixup with. Hence you are seeing null navigation properties.

This behavior was same in previous version (EF6). The main reason for not tracking is, as in your case, you are creating new Page without loading Content. If we track the new entity then it will have Content set to null (default(string)). If you mark this whole entity as modified then SaveChanges will end up saving null value in Content column in database. This would cause data loss. Due to minor error could cause major issue like data loss, EF Core does not track entities by default. Another reason is weak entity types (or complex types in EF6) which share CLR type with other entities but uniquely identified through Parent type, if you project out such entity then EF Core cannot figure out which entity type it is without parent information.

You could put those entities in changetracker by calling Attach method, which will cause fix up and you will get desired behavior. Be careful not to save them.

In general the scenario you want is useful. This issue is tracking support for that in EF Core.

这篇关于查询列子集时的EF Core修复的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆