使用预先加载的存储库通用方法GetById

我正在使用Entity Framework,并希望在Repository类中使用eager loading创建通用的GetById方法:

这是我使用延迟加载的方法:

public virtual TEntity GetById(object id) { return DbSet.Find(id); } 

我知道方法Find不支持预先加载,但是如何修改此方法以使用预先加载,以便我使用此方法如下(例如):

 _unitOfWork.MyRepository.GetById(includeProperties: "Users"); 

一种可能的方法是将DbSetInclude s的DbSet一起使用谓词。 使用Expression.Equal方法手动构建谓词并不困难,但主要的挑战是如何获取密钥属性名称。 幸运的是,我们可以使用一些ObjectContext方法来实现这一点,因此实现可能是这样的(假设我们可以访问具体的DbContext实例):

 public virtual TEntity GetById(object id, params string[] includeProperties) { var propertyName = ((System.Data.Entity.Infrastructure.IObjectContextAdapter)DbContext).ObjectContext .CreateObjectSet().EntitySet.ElementType.KeyMembers.Single().Name; var parameter = Expression.Parameter(typeof(TEntity), "e"); var predicate = Expression.Lambda>( Expression.Equal( Expression.PropertyOrField(parameter, propertyName), Expression.Constant(id)), parameter); var query = DbSet.AsQueryable(); if (includeProperties != null && includeProperties.Length > 0) query = includeProperties.Aggregate(query, System.Data.Entity.QueryableExtensions.Include); return query.FirstOrDefault(predicate); } 

这是Entity Framework Core 2.0的更新。 此外,此方法使用EF的新元数据属性自动获取第一级导航属性。

 public virtual T Get(object id) { var propertyName = "AddressId"; //get all navigation properties defined for entity var navigationProps = _context.Model.FindEntityType(typeof(T)).GetNavigations(); //turn those navigation properties into a string array var includeProperties = navigationProps.Select(p => p.PropertyInfo.Name).ToArray(); //make parameter of type T var parameter = Expression.Parameter(typeof(T), "e"); //create the lambda expression var predicateLeft = Expression.PropertyOrField(parameter, propertyName); var predicateRight = Expression.Constant(id); var predicate = Expression.Lambda>(Expression.Equal(predicateLeft, predicateRight), parameter); //get queryable var query = _context.Set().AsQueryable(); //apply Include method to the query multiple times query = includeProperties.Aggregate(query, Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.Include); //return first item in query return query.FirstOrDefault(predicate); }