问题
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.
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);
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.
However, if I query for a UserEntity
and include its PostEntity
s, 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.
}
This isn't too much trouble, but when a list of PostEntity
s are retrieved and their UserEntity
s 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?
}
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 PostEntity
s being returned when their UserEntity
s are included?
回答1:
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.
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
});
}
来源:https://stackoverflow.com/questions/34801414/preventing-automatic-population-of-circular-navigation-properties-in-entity-fram