【问题标题】:Repository generic method GetById using eager loading使用急切加载的存储库通用方法 GetById
【发布时间】:2016-09-07 14:11:23
【问题描述】:

我正在使用 Entity Framework,并希望在 Repository 类中创建通用 GetById 方法并进行预加载:

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

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

我知道Find方法不支持预加载,但是怎么可能修改这个方法来使用预加载,所以我使用这个方法如下(举例):

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

【问题讨论】:

标签: c# entity-framework repository repository-pattern


【解决方案1】:

一种可能的方法是使用带有谓词的FirstOrDefault,而不是带有Includes 的DbSet。使用Expression.Equal 方法手动构建谓词并不难,但主要挑战是如何获取关键属性名称。幸运的是,我们可以使用一些 ObjectContext 方法来做到这一点,所以实现可能是这样的(假设我们可以访问具体的 DbContext 实例):

public virtual TEntity GetById(object id, params string[] includeProperties)
{
    var propertyName = ((System.Data.Entity.Infrastructure.IObjectContextAdapter)DbContext).ObjectContext
        .CreateObjectSet<TEntity>().EntitySet.ElementType.KeyMembers.Single().Name;

    var parameter = Expression.Parameter(typeof(TEntity), "e");
    var predicate = Expression.Lambda<Func<TEntity, bool>>(
        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);
}

【讨论】:

  • 这里出现错误:var propertyName = ((IObjectContextAdapter)Context).ObjectContext .CreateObjectSet().EntitySet.ElementType.KeyMembers.Single().Name; “无法将 'System.Data.Entity.DbSet`1[Model.ProductDetail]' 类型的对象转换为 'System.Data.Entity.Infrastructure.IObjectContextAdapter'。”
  • @PranavMishra 该过程期望Context 变量为DbContext(或派生)类类型。虽然您收到的错误表明DbSet&lt;T&gt; 类型的变量。
【解决方案2】:

这是 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<Func<T, bool>>(Expression.Equal(predicateLeft, predicateRight), parameter);

        //get queryable
        var query = _context.Set<T>().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);
}

【讨论】:

    【解决方案3】:

    在存储库中使用它

    public IQueryable<T> FindByCondition(Expression<Func<T, bool>> expression)
        {
            return this.RepositoryContext.Set<T>().Where(expression).AsNoTracking();
        }
    

    这个在行动方法

    var User =  _IRepositoryWrapper.User.FindByCondition(x=>x.Id == id).Include(a=>a.Photos).FirstOrDefault();
    

    【讨论】:

    • 他们想回TEntity
    • 我不确定这是否解决了提出的问题,即如何调用急切加载。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多