我在检索具有循环引用的实体时遇到问题。我的实体导航属性不是延迟加载的,因此我希望它们返回 null,除非特别包含在查询中,但是我发现当两个实体之间存在循环引用时,情况并非如此,而是递归层次结构已返回。
例如,假设我们有两个实体 UserEntity
和PostEntity
。一个UserEntity
可以有很多帖子,但一个帖子只能有一个 UserEntity
。所以,配置如下:
// UserEntity configuration
HasMany(u => u.Posts)
.WithRequired(p => p.User);
如果我在数据库中查询 UserEntity
或PostEntity
不使用Include()
分别在Posts
或User
导航属性,导航属性按预期为 null。
但是,如果我查询 UserEntity
并包括其 PostEntity
s,返回一个循环层次结构,即使我从未要求 PostEntity.User
填充导航属性:
using (var db = new MyDbContext())
{
var user = await db.Users
.Include(u => u.Posts)
.SingleOrDefaultAsync(u => u.ID == 0);
// The [UserEntity] contains a list of [PostEntitiy]s
// each with the [UserEntity] each with a list of [PostEntitiy]s...
// and so on.
}
这并不是太麻烦,但是当列表 PostEntity
时s 被检索并且它们 UserEntity
包含在内的事情变得非常奇怪:
using (var db = new MyDbContext())
{
var posts = await db.Posts
.Include(p => p.User)
.SingleOrDefaultAsync(p => p.ID == 0);
// This throws a [System.InvalidOperationException]:
// "Sequence contains more than one element"
// How can this be? The ID is unique.
var posts = await db.Posts
.Include(p => p.User)
.Where(p => p.ID == 0)
.ToListAsync();
// This returns several copies of the PostEntity
// which should be unique in the database. Is
// this a side effect of the circular reference?
}
显然,摆脱循环引用可以解决这个问题,但有几个原因可以解释为什么保留它是有益的(如果可能的话)。 尽管 Include()
仅请求一个单向关系,但为什么 EntityFramework 仍返回此循环层次结构,以及为什么这会导致几个 PostEntity
当他们的UserEntity
时被返回包括在内吗?
最佳答案
您可以尝试将实体投影到 DTO 中来解决此问题。使用projection转换为没有此类引用的某种类型并避免异常。
换句话说,只从 EF 模型中选取所需的属性,而不是添加嵌套复杂类型的字段,这些复杂类型也具有指向同一对象的属性,从而创建循环引用
using (var db = new MyDbContext())
{
var posts = db.Posts
.Include(p => p.User)
.Where(p => p.ID == 0)
.Select(p => new PostsDTO
{
Name = p.Name,
Username = p.User.Username
});
}
关于c# - 防止 Entity Framework 中循环导航属性的自动填充,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34801414/