NotMapped property causes all properties load in select statement in EF Core

Viewed 476

I use EF Core 5 in a project, one of my entities contains a NotMapped property that mixed two properties of the entity, I expect in the select statement only properties that contain in the select statement load from the database but after profiling, I have seen that all properties were loaded.

As a sample, the Contact entity contains one NotMapped property as follows.

public class Contact
{
    public int ContactId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    [NotMapped]
    public string FullName => $"{FirstName} {LastName}";
    public string Email { get; set; } 
    public string Phone { get; set; } 
    public string Address { get; set; } 
}

public class SampleContext : DbContext
{
    public DbSet<Contact> Contacts { get; set; }
}

In the following query, I need only ContactId and FullName, I expect only ContactId, FirstName, LastName to load in the TSQL query, but all properties are loaded.

var list = dbContext.Contacts.Select( e => new
    {
        e.ContactId,
        e.FullName
    }).ToList();
2 Answers

If you just want to load some columns you could:

var list = dbContext.Contacts
    .Where(...)
    .Select( e => new
    {
        e.ContactId,
        LastName = e.FirstName + " " + e.LastName
    })
    .ToList() // hit the database 

I'm actually surprised this runs at all. The whole point of NotMapped is to indicate that the column is not bound and shouldn't even be used in a Select or any other Linq expression. With EF 6 trying that would have resulted in an error. Your choices were:

A) Select the entity and use the client-side computed property as you had declared. (Essentially what your code is doing behind the scenes)

or

B) as tymtam suggested, compute the property in the anonymous type.

var list = dbContext.Contacts
    .Where(...)
    .Select( e => new
    {
        e.ContactId,
        LastName = e.FirstName + " " + e.LastName
    }).ToList() // hit the database 

EF Core had introduced client side evaluation which was enabled by default in earlier versions but I believe disabled by default since EF Core 3... This issue smells either of that you have client side evaluation enabled, or a bug in EF Core 5 that is still reverting to a client-side evaluation for an unmapped property. Either way, I am not aware of marking a property as "client side computed" as this would only possibly work if the property was declared as an expression (rather than effectively a string.Format) so your options are either of the two above, or relying on what looks to be client side evaluation which is either something your project has configured (and potentially will bite you in the butt down the road) or a bug that may be "fixed" and stop working at some point in the future.

Related