来自文档:
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
中的Event
为null
,而Event
中的Page
为null
。
如果我用这个替换第一个查询,则修复工作正常:
var pages = _dbContext.Page.ToList();
所以看来,通过投影,修复工作不会发生。我在2个查询中将其拆分的原因是为了避免使用类似Include
的内容,这会产生巨大的连接并重复大量数据。
有什么方法吗?我是否需要自己手动修复?
答案 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
方法时使用此方法