A Better Generic Repository for Entity Framework

using System.Linq.Expressions;
using Christopher.Snay.Sample.DataAccess.Database;
using Microsoft.EntityFrameworkCore;

namespace Christopher.Snay.Sample.DataAccess.Repositories
{
	internal sealed class Repository<TEntity> : IRepository<TEntity> where TEntity : class
	{
		private readonly SampleDbContext _db;

		public Repository(SampleDbContext db)
		{
			_db = db;
		}

		public TEntity? Get(int id)
		{
			return _db.Set<TEntity>().Find(id);
		}

		public IEnumerable<TEntity> All()
		{
			return _db.Set<TEntity>().AsEnumerable();
		}

		public IEnumerable<TEntity> All<TChild>(
			Expression<Func<TEntity, TChild>> includePredicate)
		{
			return _db.Set<TEntity>().Include(includePredicate).AsEnumerable();
		}

		public IEnumerable<TEntity> All<TChild, TGrandChild>(
			Expression<Func<TEntity, TChild>> includePredicate,
			Expression<Func<TChild, TGrandChild>> thenIncludePredicate)
		{
			return _db.Set<TEntity>().Include(includePredicate)
				.ThenInclude(thenIncludePredicate).AsEnumerable();
		}

		public TEntity? Select(Expression<Func<TEntity, bool>> predicate)
		{
			return _db.Set<TEntity>().FirstOrDefault(predicate);
		}

		public TEntity? Select<TChild>(Expression<Func<TEntity, bool>> predicate,
			Expression<Func<TEntity, TChild>> includePredicate)
		{
			return _db.Set<TEntity>().Include(includePredicate).FirstOrDefault(predicate);
		}

		public TEntity? Select<TChild, TGrandChild>(
			Expression<Func<TEntity, bool>> predicate,
			Expression<Func<TEntity, TChild>> includePredicate,
			Expression<Func<TChild, TGrandChild>> thenIncludePredicate)
		{
			return _db.Set<TEntity>().Include(includePredicate)
				.ThenInclude(thenIncludePredicate).FirstOrDefault(predicate);
		}

		public IEnumerable<TEntity> SelecyMany(Expression<Func<TEntity, bool>> predicate)
		{
			return _db.Set<TEntity>().Where(predicate).AsEnumerable();
		}

		public IEnumerable<TEntity> SelecyMany<TChild>(
			Expression<Func<TEntity, bool>> predicate,
			Expression<Func<TEntity, TChild>> includePredicate)
		{
			return _db.Set<TEntity>().Include(includePredicate).Where(predicate).AsEnumerable();
		}

		public IEnumerable<TEntity> SelecyMany<TChild, TGrandChild>(
			Expression<Func<TEntity, bool>> predicate,
			Expression<Func<TEntity, TChild>> includePredicate,
			Expression<Func<TChild, TGrandChild>> thenIncludePredicate)
		{
			return _db.Set<TEntity>().Include(includePredicate)
				.ThenInclude(thenIncludePredicate).Where(predicate).AsEnumerable();
		}

		public void Insert(TEntity entity)
		{
			_db.Set<TEntity>().Add(entity);
		}

		public void Insert(List<TEntity> entities)
		{
			_db.Set<TEntity>().AddRange(entities);
		}

		public void Update(TEntity entity)
		{
			_db.Set<TEntity>().Update(entity);
		}

		public void Update(List<TEntity> entities)
		{
			_db.Set<TEntity>().UpdateRange(entities);
		}

		public void Delete(TEntity entity)
		{
			_db.Set<TEntity>().Remove(entity);
		}

		public void Delete(List<TEntity> entities)
		{
			_db.Set<TEntity>().RemoveRange(entities);
		}

		public int SaveChanges()
		{
			return _db.SaveChanges();
		}
	}

	public interface IRepository<TEntity> where TEntity : class
	{
		TEntity? Get(int id);

		IEnumerable<TEntity> All();
		IEnumerable<TEntity> All<TChild>(Expression<Func<TEntity, TChild>> includePredicate);
		IEnumerable<TEntity> All<TChild, TGrandChild>(
			Expression<Func<TEntity, TChild>> includePredicate,
			Expression<Func<TChild, TGrandChild>> thenIncludePredicate);

		TEntity? Select(Expression<Func<TEntity, bool>> predicate);
		TEntity? Select<TChild>(
			Expression<Func<TEntity, bool>> predicate,
			Expression<Func<TEntity, TChild>> includePredicate);
		TEntity? Select<TChild, TGrandChild>(
			Expression<Func<TEntity, bool>> predicate,
			Expression<Func<TEntity, TChild>> includePredicate,
			Expression<Func<TChild, TGrandChild>> thenIncludePredicate);

		IEnumerable<TEntity> SelecyMany(Expression<Func<TEntity, bool>> predicate);
		IEnumerable<TEntity> SelecyMany<TChild>(
			Expression<Func<TEntity, bool>> predicate,
			Expression<Func<TEntity, TChild>> includePredicate);
		IEnumerable<TEntity> SelecyMany<TChild, TGrandChild>(
			Expression<Func<TEntity, bool>> predicate,
			Expression<Func<TEntity, TChild>> includePredicate,
			Expression<Func<TChild, TGrandChild>> thenIncludePredicate);

		void Insert(TEntity entity);
		void Insert(List<TEntity> entities);

		void Update(TEntity entity);
		void Update(List<TEntity> entities);

		void Delete(TEntity entity);
		void Delete(List<TEntity> entities);

		int SaveChanges();
	}
}