Entity Framework Core Find method code samples

At one time or another a record needs to be located, usually developers will use FirstOrDefault or SingleOrDefault (along with First and Single) to find a single records.

When working with a primary key using the Find and FindAsync method will find entities in the added state that are not yet persisted while the Where method will not and need to query the database. Also, in many cases Find will be a good deal faster than Where.

What developers need to do is learn what methods are available and work with the appropriate method for a specific task e.g. a model has City name, using Find will not work as it's used on primary keys while FirstOrDefault to find the first city interested in or Where to find all cities interested in.

Here the Customers table has a single primary key, FindAsync will if a entity is located with the key passed in keys will record an entity while navigation properties will not be included.

See in repository.

public static async Task<Customers> FindCustomersAsync(object[] keys)
{
 
    using (var context = new NorthwindContext())
    {
        var customer = await context.Customers.FindAsync(keys);
        return customer;
    }
 
}
While in this example navigation properties will be includes.

public static async Task<Customers> GetWithAllNavigationProperties(int identifier)
{
    using (var context = new NorthwindContext())
    {
 
        var customer = await context.Customers.FindAsync(identifier);
 
        foreach (NavigationEntry navigation in context.Entry(customer).Navigations)
        {
            await navigation.LoadAsync();
        }
 
        return customer;
    }
 
}

We can also have a method to specify which navigation properties to include as shown in the following. For those want a generic method here is a class which can be used.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using NorthEntityLibrary.Contexts;
using NorthEntityLibrary.Interfaces;
using NorthEntityLibrary.Models;
 
namespace NorthEntityLibrary.Repositories
{
    /// <summary>
    /// Popular generic method to include navigation properties
    /// </summary>
    /// <typeparam name="TEntity">Model</typeparam>
    public class GenericRepository<TEntity> : IGenericOperations<TEntity> where TEntity : class
    {
        private readonly NorthwindContext _context;
        private readonly DbSet<TEntity> _dbSet;
 
        /// <summary>
        /// Initialize DbContext and Model
        /// </summary>
        public GenericRepository()
        {
            _context = new NorthwindContext();
            _dbSet = _context.Set<TEntity>();
        }
 
        /// <summary>
        /// Get entity by primary key
        /// </summary>
        /// <param name="identifier">primary key to find</param>
        /// <param name="references">empty, one or more navigation property by name</param>
        /// <returns>Entity if found along with navigation items if specified</returns>
        public async Task<TEntity> GetTask(int identifier, string[] references = null)
        {
            var model = await _dbSet.FindAsync(identifier);
 
            if (references == null) return model;
 
            foreach (var reference in references)
            {
                _context.Entry((object)model).Reference(reference).Load();
            }
 
            return model;
 
        }
        /// <summary>
        /// Get entity by primary key
        /// </summary>
        /// <param name="identifier">primary key to find</param>
        /// <param name="references">empty, one or more navigation property by name</param>
        /// <returns>Entity if found along with navigation items if specified</returns>
        public TEntity Get(int identifier, string[] references = null)
        {
            var model = _dbSet.Find(identifier);
 
            if (references == null) return model;
 
            foreach (var reference in references)
            {
                _context.Entry((object)model).Reference(reference).Load();
            }
 
            return model;
 
        }
        /// <summary>
        /// Get entity by primary key
        /// </summary>
        /// <param name="identifier">primary key to find</param>
        /// <returns>Entity if found all navigation(s) are included</returns>
        public async Task<TEntity> GetWithIncludesTask(int identifier)
        {
            var model = await _dbSet.FindAsync(identifier);
 
            foreach (NavigationEntry navigation in _context.Entry(model).Navigations)
            {
                await navigation.LoadAsync();
            }
 
            return model;
 
        }
        /// <summary>
        /// Get entity by primary key
        /// </summary>
        /// <param name="identifier">primary key to find</param>
        /// <returns>Entity if found all navigation(s) are included</returns>
        public TEntity GetWithIncludes(int identifier)
        {
            var model = _dbSet.Find(identifier);
 
            foreach (NavigationEntry navigation in _context.Entry(model).Navigations)
            {
                navigation.Load();
            }
 
            return model;
 
        }
        /// <summary>
        /// Get all with no navigation properties, one or more navigation properties
        /// </summary>
        /// <param name="navigationProperties">Navigation properties</param>
        /// <returns>List of TEntity</returns>
        public virtual IList<TEntity> GetAll(params Expression<Func<TEntity, object>>[] navigationProperties)
        {
            List<TEntity> list;
 
            using (var context = new NorthwindContext())
            {
                IQueryable<TEntity> dbQuery = context.Set<TEntity>();
 
                foreach (Expression<Func<TEntity, object>> navigationProperty in navigationProperties)
                {
                    dbQuery = dbQuery.Include(navigationProperty);
                }
 
                list = dbQuery
                    .AsNoTracking()
                    .ToList<TEntity>();
            }
 
            return list;
 
        }
       
    }
}

There several variations that can be done using Find and FindAsync which can be found in the following GitHub repository using a class project for Entity Framework Core 3.x using a modified version of Microsoft NorthWind database and tested with unit test.

Source

GitHub repository

To run the code using Visual Studio 2017 or higher

  • Open the database script in SSMS or in Visual Studio.
  • Change the path to where the database will be created at the top of the script.
  • Run the script to create and populate the database.
  • Open the solution in Visual Studio
  • Right click on the top node of Solution Explorer, select "Restore NuGet packages"
  • Build the solution.
  • Run the unit test.

Testing

Once all test have run successfully.
  • Pick each unit test method and traverse backwards to the code which is executed.
  • At each move through study the code rather than simply glancing.

How to use in your projects

  • Add the Interface and generic repository.
  • Change the DbContext to match your DbContext, currently it's set to the project's DbContext NorthwindContext.
  • Alter and rename as you see fit as the method names are not gospel.
  • Create classes for each model and implement the Interface 

In closing

Never simply use the first method found e.g. Where or First for example, learn about each method and work with the methods outside of a project until comfortable with them unless you are a season developer who has the ability to work through new methods be it in Entity Framework Core or without Entity Framework Core that are not EF Core specific.



Comments

Popular posts from this blog

VB.NET Working with Delegate and Events

Coders asking questions in online forums

GitHub download partial repository