The problem source
This isn't an EF behavior, it's an Automapper behavior.
public IQueryable<BookDTO> Get()
{
var books = dbContext.Book;
var dto = books.ProjectTo<BookDTO>(_mapper.ConfigurationProvider);
return dto;
}
ProjectTo<>
intentionally selects all properties that it can map to. If you tell it to project to a BookDTO
, it will do its best to fill all of the properties defined in BookDTO
, which includes the author.
Further explanation
Entity Framework has certain behaviors in regards to loading navigational properties, generally described as lazy and eager loading. Initially, you'd think that this was the source of the problem.
However, when you use a Select
, you effectively override EF's loading behaviors and tell it explicitly what it should load for you. This is by intention, to be used in cases where EF's simple behaviors don't provide the precise control that you're looking for.
You're not using a Select
, but you are using ProjectTo<>
which internally uses a Select
(which it generates based on the Automapper configuration), which means that as far as EF is concerned, you are overriding the loading behavior and "you" (i.e. Automapper) are explicitly telling EF to load the author.
The solution(s)
You can tell Automapper to ignore a property using the correct attribute:
public partial class Book
{
public int BookId { get; set; }
public int AuthorId { get; set; }
public string Title { get; set; }
[NotMapped]
public Author Author { get; set; }
}
This will lead to Automapper not fetching the related author from the database.
However, part of the strength of ProjectTo<>
is that you no longer have to manage what you do/don't want to load and instead let Automapper figure it out based on the provided DTO. It's not too bad to put one attribute on a DTO, but if you start applying this on a large scale, it's going to increase development and maintenance complexity.
Instead, I would suggest you create two separate DTO classes, one with Author information and one without. That way, you don't have to manually control the mapping behavior (any more than you should), and it'll also save you on a bunch of null checks that you don't need to perform when handling this DTO without its author being loaded as well.