防止在Entity Framework中自动填充圆形导航属性 [英] Preventing automatic population of circular navigation properties in Entity Framework

查看:118
本文介绍了防止在Entity Framework中自动填充圆形导航属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

检索具有循环引用的实体时出现问题.我的实体导航属性不是延迟加载的,因此,除非明确包含在查询中,否则我希望它们返回null,但是我发现,当两个实体之间存在循环引用时,情况并非如此,而是递归层次结构返回.

I have a problem when retrieving entities which have a circular reference. My entity navigation properties are not lazy loaded, so I would expect them to return null unless specifically included in a query, however I've found that when there is a circular reference between two entities this isn't the case and instead a recursive hierarchy is returned.

例如,假设我们有两个实体UserEntityPostEntity. UserEntity可能有很多帖子,但是一个帖子只能有一个UserEntity.因此,配置如下:

For example, let's say we have two entities UserEntity and PostEntity. A UserEntity may have many posts, but a post must only have a single UserEntity. So, the configuration is as follows:

// UserEntity configuration
HasMany(u => u.Posts)
  .WithRequired(p => p.User);

如果我在相应的PostsUser导航属性上不使用Include()的情况下查询数据库的UserEntityPostEntity,则导航属性为空.

If I query the database for either a UserEntity or a PostEntity without using Include() on the respective Posts or User navigation properties, the navigation properties are null as expected.

但是,如果我查询UserEntity并包含它的PostEntity,即使我从未要求填充PostEntity.User导航属性,也会返回循环层次结构:

However, if I query for a UserEntity and include its PostEntitys, an circular hierarchy is returned, even though I never requested that the PostEntity.User navigation property be populated:

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的列表并包含它们的UserEntity时,事情会变得很奇怪:

This isn't too much trouble, but when a list of PostEntitys are retrieved and their UserEntitys are included things get very weird:

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为什么仍返回此循环层次结构?为什么会导致包含UserEntity的多个PostEntity被返回,而又导致多个PostEntity返回? strong>

Obviously getting rid of the circular reference would fix this, but there are several reasons why keeping it is beneficial, if possible. Why is EntityFramework returning this circular hierarchy despite only a single, one-way relationship being requested with Include(), and why is this resulting in several PostEntitys being returned when their UserEntitys are included?

推荐答案

您可以尝试将实体投影到DTO中以解决此问题.使用投影到某种不会有这样的引用,请避免例外.

You could try projecting your entities into DTOs to work around this. Use projection into some type that does not have such references and avoid the exception.

换句话说,仅从EF模型中选取所需的属性,而不添加嵌套复杂类型的嵌套字段,这些复杂类型也具有指向同一对象的属性,从而创建循环引用

In other words, pick up just the properties that you need from the EF model, not adding fields which are nested complex types that also have properties that point back to the same object and thus create circular references

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

这篇关于防止在Entity Framework中自动填充圆形导航属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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