簡體   English   中英

使用實體框架在IRepository模式中創建where或any子句

[英]Make a where or any clause in a IRepository pattern with entity framework

我接管了一個使用IRepository模式的同事的項目。 我以前從未使用它,所以我在理解如何制作WHERE子句或ANY子句時遇到一些問題。

以前我有以下代碼,它使用DataContext存儲庫(實際的實現,我可以在where子句中使用where:

        IQueryable<Office> officeList = repository.Offices;

        if (specification.CountryId > 0)
        {
            officeList = repository.Offices.Where(c => c.CountryId == specification.CountryId);
        }
        if (specification.LetterSize != null)
        {
            officeList =
                officeList.Where(
                    c => c.OfficeProducts.Any(d => d.OfficeProductDetail.Size == (int)specification.LetterSize));
        }

        return officeList.ToList();

我想了解如何使用上面的代碼片段來使用IRepository模式。 我試圖實現WHERE / QUERY,但無法使其工作。

我的問題:

  • 你如何在實踐中實現WHERE / ANY語句,所以我可以做一些像上面的代碼片段?

我的IRepository

public interface IRepository
    {
        T GetById<T>(long id) where T : class;
        void Create<T>(T entity) where T : class;
        void Update<T>(T entity) where T : class;
        void SaveOrUpdate<T>(T entity) where T : class;
        void Delete<T>(T entity) where T : class;

        IList<T> FindAll<T>(params OrderBy[] orders) where T : class;
        int Count<T>(Expression<Func<T, bool>> whereExpression) where T : class;
        bool Exists<T>(Expression<Func<T, bool>> whereExpression) where T : class;

        T FindFirst<T>(Expression<Func<T, bool>> whereExpression, params OrderBy[] orders) where T : class;
        PaginatedResult<T> Find<T>(Expression<Func<T, bool>> whereExpression, int pageIndex, int pageSize, params OrderBy[] orders) where T : class;

        void ExecuteNativeSQL(string sql);
    }

實施:

public class EFRepository : IRepository
    {
        private IDBFactory databaseFactory;
        private LetterAmazerContext dataContext;

        public EFRepository(IDBFactory databaseFactory)
        {
            this.databaseFactory = databaseFactory;
        }

        protected LetterAmazerContext DataContext
        {
            get { return dataContext ?? (dataContext = databaseFactory.Get()); }
        }

        public T GetById<T>(long id) where T : class
        {
            IDbSet<T> dbset = DataContext.Set<T>();
            return dbset.Find(id);
        }

        public void Create<T>(T entity) where T : class
        {
            IDbSet<T> dbset = DataContext.Set<T>();
            dbset.Add(entity);
        }

        public void Update<T>(T entity) where T : class
        {
            dataContext.Entry(entity).State = EntityState.Modified;
        }

        public void SaveOrUpdate<T>(T entity) where T : class
        {
            throw new NotImplementedException();
        }

        public void Delete<T>(T entity) where T : class
        {
            IDbSet<T> dbset = DataContext.Set<T>();
            dbset.Remove(entity);
        }

        public IList<T> FindAll<T>(params OrderBy[] orders) where T : class
        {
            IDbSet<T> dbset = DataContext.Set<T>();
            var query = dbset.Where(t => true);
            query = ApplyOrders<T>(query, orders);
            return query.ToList<T>();
        }

        public int Count<T>(Expression<Func<T, bool>> whereExpression) where T : class
        {
            IDbSet<T> dbset = DataContext.Set<T>();
            return dbset.Count<T>(whereExpression);
        }

        public bool Exists<T>(Expression<Func<T, bool>> whereExpression) where T : class
        {
            IDbSet<T> dbset = DataContext.Set<T>();
            return dbset.Count<T>(whereExpression) != 0;
        }

        public T FindFirst<T>(Expression<Func<T, bool>> whereExpression, params OrderBy[] orders) where T : class
        {
            IDbSet<T> dbset = DataContext.Set<T>();
            var query = dbset.Where(whereExpression);
            query = ApplyOrders<T>(query, orders);
            return query.SingleOrDefault<T>();
        }

        public PaginatedResult<T> Find<T>(Expression<Func<T, bool>> whereExpression, int pageIndex, int pageSize, params OrderBy[] orders) where T : class
        {
            IDbSet<T> dbset = DataContext.Set<T>();
            PaginatedResult<T> results = new PaginatedResult<T>();
            var query = dbset.AsExpandable().Where(whereExpression);
            query = ApplyOrders<T>(query, orders);
            results.Results = query.Skip<T>(pageIndex * pageSize).Take<T>(pageSize).ToList<T>();
            results.TotalItems = dbset.AsExpandable().LongCount(whereExpression);
            return results;
        }

        public void ExecuteNativeSQL(string sql)
        {
            DataContext.Database.ExecuteSqlCommand(sql);
        }

        private IQueryable<T> ApplyOrders<T>(IQueryable<T> query, params OrderBy[] orders)
        {
            if (orders == null || orders.Length == 0) return query;
            foreach (var order in orders)
            {
                query = query.OrderBy(order.ToString());
            }
            return query;
        }
    }

您的存儲庫目前正在為任意表達式打開,包括實現無法評估的潛在表達式。

一方面,這是一個潛在的風險,無法提供符合如此開放合同的實施。

另一方面,為什么不再將它暴露出來呢:

public interface IRepository
{
    ...
    IQueryable<T> Query<T>();
}

public class EFRepository : IRepository
{
   ...
   public IQueryable<T> Query<T>()
   {
       return DataContrxt.Set<T>();
   }
}

請注意,如果您決定采用這種方式,那么大多數特定查詢方法都不再有意義,因為這種開放式通用可查詢接口滿足了大多數需求。

另請注意,同樣的問題也適用於此,如果您有多個實現,則無法保證以相同的方式滿足合同。 此外,您的潛在客戶可以輕松創建提供商拒絕的查詢。 如果您接受這些問題,建議的解決方案將解決您的問題,因為您現在可以查詢存儲庫幾乎所有內容。

最后一點,如果您不打算有多個實現,請完全刪除存儲庫層。 EF上下文內部存儲庫的工作單元。 從版本6開始,可以模擬上下文,因此可以進行單元測試。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM