【问题标题】:Where to place multiple queries for repository在哪里放置存储库的多个查询
【发布时间】:2014-04-18 15:05:53
【问题描述】:

我不确定将我的特定业务对象查询放在哪里。

当我们开始对存储库模式使用多个特定于表的查询时,其中 应该放置这些吗?服务层还是存储库?

例如请看下面:

例如:

class HR_Repository<T> : IRepository<T> where T : class
{
private readonly  LoginDataContext dataContext;
public HR_Repository(LoginDataContext dataContext)
{
this.dataContext = dataContext;
}
public void Commit()
{
    dataContext.SubmitChanges();
}

public IList<T> FindAll()
{
    var table = this.LookupTableFor(typeof(T));
    return table.Cast<T>().ToList();
}

public IQueryable<T> Find()
{
    var table = this.LookupTableFor(typeof(T));
    return table.Cast<T>();
}

public void Add(T item)
{
    var table = this.LookupTableFor(typeof(T));
    table.InsertOnSubmit(item);
}   

public void Delete(T item)
{
    var table = this.LookupTableFor(typeof(T));
    table.DeleteOnSubmit(item);
}

private ITable LookupTableFor(Type entityType)
{
    return dataContext.GetTable(entityType);
}



}

我目前在存储库中有这个类。但我计划为其他桌子放置更多这些。这对我来说“感觉”不对。

诸如此类的多个课程是否会被视为最佳实践或不受欢迎?:

public static class UserQueries
    {
        public static Employee ByUserName(this IQueryable<Employee> employees, string username)
        {
            return employees.Where(u => u.User_Name == username).FirstOrDefault();
        }
    }

此外,我计划使用另一种方法 (GetEmployeeProductivity),该方法本质上是使用 Employee 对象中的数据和在单独的 DataRepository 中找到的数据来应用逻辑。所以现在我使用的是 EmployeeRepository 和 DataRepository。

这会去哪里?员工类、服务还是存储库?

【问题讨论】:

  • 你使用依赖注入吗?您应该创建服务来处理从数据库中获取数据并将其格式化为理想的视图模型!
  • 不,我目前没有。

标签: c# design-patterns repository-pattern


【解决方案1】:

通常,您根据业务规则做出决策的逻辑位于服务层。从表中创建、更新或删除行的代码(标准 CRUD 函数)进入存储库。

因此,如果您需要通过将多个表连接在一起来检索数据,那就在存储库中。 “如果满足此条件,则对数据库执行此操作”的代码位于服务层中。如果您需要在多个表中添加或更新一行,那仍然在存储库中,并且可以通过一种方法完成(如果 2 个表在概念上是一个,但出于数据库效率的原因分为两个,例如一个多或多对多关系),或者您可以使用单独的方法,每个表一个,然后从服务层中的一个方法调用它们。

【讨论】:

  • 这是有道理的。但是,这将如何应用于我的示例?
  • 您的GetEmployeeProductivity 听起来肯定会进入服务层。你的UserQueries 类也可以进入服务层。我的应用程序有一个页面,它是一个搜索页面。用户指定搜索条件,并使用单独的 BackgroundWorker 对象搜索两个不同的表。构建 EF 查询的方法位于服务层中,但它们都调用存储库层中的方法,将它们构建的查询传递给存储库层中的方法,这些方法检索数据。
  • 如果您的服务层构建查询,那么它会耦合到 EF,即数据库。如果服务正常工作,存储库负责什么?您已经有 EF 抽象数据库。
  • 对于这一屏,服务层构建了一个IQueryable。执行IQueryable 和处理任何 EF 错误的代码在存储库中。当不同的服务层方法按 ID 从表中返回一行时,调用相同的存储库方法以从该表中返回一行。它将IQueryable 和实体上下文作为参数。服务层方法是应用业务逻辑,例如对最终 SQL 查询的 WHERE 子句应用权限,以及用户在屏幕上应用的条件。
【解决方案2】:

您还可以将它们封装在它们引用的每个类中。您的第二个静态类具有方法 ByUserName,它返回一个 Employee 对象。您可以将此方法放在 Employee 类中(存储库:EmployeeRepository)。但是你有很多选择。在团队中工作时,如果一切都井井有条,应该会更好。

【讨论】:

    【解决方案3】:

    由于设计模式与repository/UnitOfWork模式相比有很多想法,这里是repository & business layer的标准实现。

    ***DATA LAYER***
    
    namespace app.data
    {
        public interface IGenericDataRepository<T> where T : class
        {
            IList<T> GetAll(params Expression<Func<T, object>>[] navigationProperties);
            IList<T> GetList(Func<T, bool> where, params Expression<Func<T, object>>[] navigationProperties);
            T GetSingle(Func<T, bool> where, params Expression<Func<T, object>>[] navigationProperties);
            void Add(params T[] items);
            void Update(params T[] items);
            void Remove(params T[] items);
        }
    
    }
    
    namespace app.data
    {
        public class GenericDataRepository<T> : IGenericDataRepository<T> where T : class
        {
            public virtual IList<T> GetAll(params Expression<Func<T, object>>[] navigationProperties)
            {
                List<T> list;
                using (var context = new GatePassEntities())
                    {
                    IQueryable<T> dbQuery = context.Set<T>();
    
                    //Apply eager loading
                    foreach (Expression<Func<T, object>> navigationProperty in navigationProperties)
                        dbQuery = dbQuery.Include<T, object>(navigationProperty);
    
                    list = dbQuery
                        .AsNoTracking()
                        .ToList<T>();
                }
                return list;
            }
    
            public virtual IList<T> GetList(Func<T, bool> where,
                 params Expression<Func<T, object>>[] navigationProperties)
            {
                List<T> list;
                using (var context = new GatePassEntities())
                {
                    IQueryable<T> dbQuery = context.Set<T>();
    
                    //Apply eager loading
                    foreach (Expression<Func<T, object>> navigationProperty in navigationProperties)
                        dbQuery = dbQuery.Include<T, object>(navigationProperty);
    
                    list = dbQuery
                        .AsNoTracking()
                        .Where(where)
                        .ToList<T>();
                }
                return list;
            }
    
            public virtual T GetSingle(Func<T, bool> where,
                 params Expression<Func<T, object>>[] navigationProperties)
            {
                T item = null;
                using (var context = new GatePassEntities())
                {
                    IQueryable<T> dbQuery = context.Set<T>();
    
                    //Apply eager loading
                    foreach (Expression<Func<T, object>> navigationProperty in navigationProperties)
                        dbQuery = dbQuery.Include<T, object>(navigationProperty);
    
                    item = dbQuery
                        .AsNoTracking() //Don't track any changes for the selected item
                        .FirstOrDefault(where); //Apply where clause
                }
                return item;
            }
    
            public virtual void Add(params T[] items)
            {
                using (var context = new GatePassEntities())
                {
                    foreach (T item in items)
                    {
                        context.Entry(item).State = EntityState.Added;
                    }
                    context.SaveChanges();
                }
            }
    
            public virtual void Update(params T[] items)
            {
                using (var context = new GatePassEntities())
                {
                    foreach (T item in items)
                    {
                        context.Entry(item).State = EntityState.Modified;
                    }
                    context.SaveChanges();
                }
            }
    
            public virtual void Remove(params T[] items)
            {
                using (var context = new GatePassEntities())
                {
                    foreach (T item in items)
                    {
                        context.Entry(item).State = EntityState.Deleted;
                    }
                    context.SaveChanges();
                }
            }
    
        }
    }
    
    //Domain Models like Employee, Department can be your objectcontext, dbcontext (can be generated by EF or other ORM Tools like T4)
    namespace app.data
    {
        public interface IEmployeeRepository : IGenericDataRepository<Employee>
        {
        }
    
        public interface IDepartmentRepository : IGenericDataRepository<Department>
        {
        }
    }
    
    ***BUSINESS LAYER***
    
    namespace app.business
    {
        public interface IBusinessLayer
        {
            IList<Employee> GetAllEmployees();
            IList<Employee> GetEmployeesByCountryName(string countryName);
            Employee GetEmployeeByName(string EmployeeName);
            Employee GetEmployeeByIdentityId(int identityId, string EmployeeUniqueIdentityNumber);
            void AddEmployee(params Employee[] Employees);
            void UpdateEmployee(params Employee[] Employees);
            void RemoveEmployee(params Employee[] Employees);
        }
    }
    
    public class BuinessLayer : IBusinessLayer
    {
     private readonly IEmployeeRepository _EmployeeRepository;
    
    
            public BuinessLayer()
            {
                _EmployeeRepository = new EmployeeRepository();
    
            }
    
            public BuinessLayer(IEmployeeRepository EmployeeRepository)
            {
                _EmployeeRepository = EmployeeRepository;
    
            }
    
            public IList<Employee> GetAllEmployees()
            {
                return _EmployeeRepository.GetAll();
            }
    
            public IList<Employee> GetEmployeesByCountryName(string countryName)
            {
                return _EmployeeRepository.GetList(e => e.Country.Employees.Equals(countryName));
            }
    
            public Employee GetEmployeeByName(string EmployeeName)
            {
                return _EmployeeRepository.GetSingle(
                    d => d.Name.Equals(EmployeeName),
                    d => d.Country); //include related employees
            }
    
            public Employee GetEmployeeByIdentityId(int identityId, string EmployeeUniqueIdentityNumber)
            {
                var EmployeeIdentity = _EmployeeIdentityRepository
                    .GetSingle
                    (
                    q => q.IdentityId == identityId && q.UniqueIdentityNumber == EmployeeUniqueIdentityNumber);
                Employee Employee = new Employee();
                if (EmployeeIdentity != null)
                {
                    Employee = _EmployeeRepository.GetSingle(o => o.EmployeeId == EmployeeIdentity.EmployeeId);
                }
                else
                    Employee = null;
                return Employee;
            }
    
            public void AddEmployee(params Employee[] Employees)
            {
                try
                {
                    _EmployeeRepository.Add(Employees);
                }
                catch (DbEntityValidationException dbEx)
                {
                    foreach (var validationErrors in dbEx.EntityValidationErrors)
                    {
                        foreach (var validationError in validationErrors.ValidationErrors)
                        {
                            Trace.TraceInformation("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
                        }
                    }
                }
    
            }
    
            public void UpdateEmployee(params Employee[] Employees)
            {
                /* Validation and error handling omitted */
                _EmployeeRepository.Update(Employees);
            }
    
            public void RemoveEmployee(params Employee[] Employees)
            {
                /* Validation and error handling omitted */
                _EmployeeRepository.Remove(Employees);
            }
    }
    

    现在可以从前端调用业务层了

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-05-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多