문제

I have the following model:

A User has a collection of Photos. In the Photo model, there is a property called IsProfilePhoto.

When I do the following, the results are not as expected.

var user = dbContext.Users.SingleOrDefault(u => u.Id == 1);
var profilePhoto = user.Photos.SingleOrDefault(p => p.IsProfilePhoto);

With lazy loading on, this performs two queries.

The first one gets the user by id as expected. The second one however, gets the collection of photos by user id and then in memory does the match on IsProfilePhoto.

I was hoping that with lazy loading on it would add the SingleOrDefault to the query as well.

Is this just not possible and I must always do the inverse? E.g.

var profilePhoto = dbContext.Photos.SingleOrDefault(p => p.UserId == 1 && p.IsProfilePhoto);
var user = profilePhoto.User;

I get the reasoning, there are just certain reasons why it's more convenient to go from the User to get the profile photo.

도움이 되었습니까?

해결책

You can get the result with a single database query by using a projection:

var userWithProfilePhoto = dbContext.Users
    .Where(u => u.Id == 1)
    .Select(u => new
    {
        User = u,
        ProfilePhoto = u.Photos.Where(p => p.IsProfilePhoto).FirstOrDefault()
    })
    .SingleOrDefault();

userWithProfilePhoto.User and userWithProfilePhoto.ProfilePhoto are the two entities you are looking for.

다른 팁

You have to use Eagerly loading to load multiple levels. Lazy load, loads the level when you access this.

var user = dbContext.Users.Include(u => u.Photos).SingleOrDefault(u => u.Id == 1);
var profilePhoto = user.Photos.SingleOrDefault(p => p.IsProfilePhoto);

This is the subtle difference in LINQ methods.

You can do the filtering as part of the query as:

var profilePhoto = user.Photos.Where(p => p.IsProfilePhoto).SingleOrDefault();

Due to this behavior in LINQ to Entities, I try to always use the Where method for the condition and the parameterless overloads for First, Single, FirstOrDefault, SingleOrDefault, Any, and Count.

Edit:

My bad, MSDN mentions it directly, but any reference to a navigation property (when lazy loading is enabled) loads all of the related records.

My best suggestion then is to a) accept extra database access, or b) query as you did in your alternative example, with the first table being the 'many' of the 'one-to-many' relationship.

First, and FirstOrDefault are lazy loaded, Single, and SingleOrDefault eagerly loaded. If you don't need a an exception thrown in case of several items returned by the query, you can change it to FirstOrDefault.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top