【问题标题】:Entity Framework Generic repository including properties through parameter实体框架通用存储库,包括通过参数的属性
【发布时间】:2018-12-29 11:14:32
【问题描述】:

我在实体框架中有一个通用存储库的实现,我正在尝试改进它以使用 EF 提供的 .Include(..) 函数,而不是按字符串包含导航属性,以便能够安全地重命名属性。

以下是我当前的代码:

public IQueryable<T> GetAll(
        Expression<Func<T, bool>> filter = null,
        Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null,
        string includeProperties = "")
    {
        IQueryable<T> query = dbSet;

        if (filter != null)
        {
            query = query.Where(filter);
        }

        foreach (var includeProperty in includeProperties.Split
            (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
        {
            query = query.Include(includeProperty);
        }

        if (orderBy != null)
        {
            return orderBy(query);
        }
        else
        {
            return query;
        }
    }

我目前的使用方式如下:

repository.GetAll(
    u => u.Name = "John",
    u => u.OrderBy(x => x.Name),
    "Address.State",
);

我的问题是:如何更改方法以便能够以以下方式(或类似方式)调用它:

repository.GetAll(
    u => u.Name = "John",
    u => u.OrderBy(x => x.Name),
    u => u.Include(x => x.Address).ThenInclude(x => x.State),
);

【问题讨论】:

    标签: c# entity-framework .net-core


    【解决方案1】:

    我建议你保留两种方法,一种接受字符串参数和一种表达式参数。存储库的一些客户端可以更好地使用字符串签名,其中一些客户端可以更好地使用为它们带来 IntelliSense 的表达式签名。

    public IQueryable<T> GetAll(params string[] including)
    {
        var query = dbSet.AsQueryable();
        if (including != null)
            including.ToList().ForEach(include =>
            {
                if (!string.IsNullOrEmpty(include))
                    query = query.Include(include);
            });
        return query;
    }
    
    public IQueryable<T> GetAll(params Expression<Func<T, object>>[] including)
    {
        var query = dbSet.AsQueryable();
        if (including != null)
            including.ToList().ForEach(include =>
            {
                if (include != null)
                    query = query.Include(include);
            });
        return query;
    }
    

    确保您已添加using System.Data.Entity;

    您可以以相同的方式实现过滤和排序的逻辑。对于过滤和排序的字符串参数签名,您可以使用System.Linq.Dynamic包。

    示例:

    var result1 = schoolRepository.GetAll("Students", "Teachers");
    var result2 = schoolRepository.GetAll(x=>x.Students, x=>x.Teachers);
    

    【讨论】:

      【解决方案2】:
      protected internal IQueryable<TEntity> Filter(Expression<Func<TEntity, bool>> predicate, params Expression<Func<TEntity, object>>[] includeProperties)
      {
          var query = RetrieveQuery();
      
          if (predicate != null)
          {
              query = query.Where(predicate).AsQueryable();
          }
      
          if (includeProperties != null)
          {
              query = _queryableUnitOfWork.ApplyIncludesOnQuery(query, includeProperties);
          }
      
          return (query);
      }
      

      这个方法在那里调用

      public IQueryable<TEntity> ApplyIncludesOnQuery<TEntity>(IQueryable<TEntity> query, params Expression<Func<TEntity, object>>[] includeProperties) where TEntity : class, IEntity
      {
          // Return Applied Includes query
          return (includeProperties.Aggregate(query, (current, include) => current.Include(include)));
      }
      

      过滤方法调用

       public IEnumerable<ShowStockProductDto> GetActiveShowStockProductListByProduct(int productId)
                  {
                      var foundedPStockroducts = Filter(
                          ent => ent.ProductId == productId && ent.IsActive,
                          ent => ent.StockProductPrices,
                          ent => ent.StockProductDepots,
                          ent => ent.StockProductSpecificationValues,
                          ent => ent.StockProductSpecificationValues.Select(spsv => spsv.SpecificationValue)
                          );
      
                      // Map foundedPStockroducts to showStockProductList
                      var showStockProductList = TypeAdapterFactory.Adapter.Adapt<IEnumerable<ShowStockProductDto>>(foundedPStockroducts).ToList();
      
                      return (showStockProductList);
                  }
      

      【讨论】:

      • 几天前在我自己的项目中处理这个问题
      • 是的,我是刚回答 stackoverflow 问题的新手,非常欢迎:/
      • @NaDeR-Star 为什么需要以下 2 行:ent => ent.StockProductSpecificationValues, ent => ent.StockProductSpecificationValues.Select(spsv => spsv.SpecificationValue)
      • 包含 StockProductSpecificationValues 集合的 SpecificationValue 导航属性
      • ent => ent.StockProductSpecificationValues 是一个集合,而 ent => ent.StockProductSpecificationValues.Select(spsv => spsv.SpecificationValue) 是一个导航
      【解决方案3】:

      您可以使用params Expression&lt;Func&lt;T, object&gt;&gt;[] includeProperties 代替字符串参数

      public IQueryable<T> GetAll(
          Expression<Func<T, bool>> filter = null,
          Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null,
          params Expression<Func<T, object>>[] includeProperties)
      {
          IQueryable<TEntity> query = dbSet;
      
              if (filter != null)
              {
                  query = query.Where(filter);
              }
      
              foreach (var includeProperty in includeProperties)
              {
                  query = query.Include(includeProperty);
              }
      
              if (orderBy != null)
              {
                  return orderBy(query);
              }
              else
              {
                  return query;
              }
      }
      

      【讨论】:

      • 如何从列表中包含子属性。例如: includeProperties: u => u.Addresses.Select(a => a.State.Country) 应该为我拉取用户的地址列表,每个用户都填充了状态,但它却抛出了一个错误跨度>
      猜你喜欢
      • 2018-07-04
      • 1970-01-01
      • 1970-01-01
      • 2023-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多