【问题标题】:In the Repository Pattern, where should I implement a Distinct method?在存储库模式中,我应该在哪里实现 Distinct 方法?
【发布时间】:2014-06-07 06:23:35
【问题描述】:

我有标准的存储库接口设置:

public interface IRepository<T, TKey> : IDisposable where T : class
{
    T Get(TKey id);
    IEnumerable<T> Get();
    IEnumerable<T> Find(Expression<Func<T, bool>> whereClause);
    T Add(T entity);
    void Delete(T entity);
    bool Save();
    int Update(T entity);
}

并且有一个实现:

public class EfRepository<T, TKey> : IRepository<T, TKey> where T : class
{
    protected DbContext _context;

    public EfRepository(DbContext context) { ...}

    public virtual T Get(TKey id) {...}
    public virtual IEnumerable<T> Get() { ...}

    public virtual IEnumerable<T> Find(Expression<Func<T, bool>> whereClause)  { ...}
    public T Add(T entity) { ...}
    public void Delete(T entity) { ...}
    public bool Save() { ...}
    public int Update(T entity) { ...}
}

在这之上还有一个服务层:

public class VehicleService: IVehicleService
{
    private readonly IRepository<Vehicle, int> _repository;

    public VehicleService(IRepository<Vehicle, int> repository)
    {
        _repository = repository;
    }

    public IEnumerable<int> GetModelYears()
    {
        // ?? help?
    }
}

我的问题是,在哪里实现 Distinct 方法? LINQ 查询如下所示:

context.Set<Vehicle>().Select(x => x.ModelYear).Distinct();

我还没有弄清楚如何在存储库级别对 Distinct 方法进行通用编码,而且我认为这不是放置它的正确位置。

我们已选择不在我们的存储库中返回 IQueryable。但我也没有向服务层公开任何实际的 DbSet 对象。

也许更好的问题是,这是一种正确的做事方式吗?有没有更好的办法?

【问题讨论】:

  • 废话,有 2 个用户给出了我要回答的问题,但我如何确定让谁成为“已接受”?我让他们争吵吗?
  • 这一切都取决于你,伙计;)
  • 接受了 thsoren 的回答,因为它更详细。但也赞成 user902553 的回答,因为它基本上是同一件事并提供选项/解释。谢谢你们。

标签: c# entity-framework repository distinct


【解决方案1】:

如果这只是用于一种对象,而不是用于存储库中的所有对象,您可以创建一个新的存储库,包含该查询,但建立在 IRepository 之上。

public interface IVehicleRepository : IRepository<Vehicle>{
    IEnumerable<int> GetDistinctVehicle();
}

public VehicleRepository : EfRepository<Vehicle>, IVehicleRepository{

    public VehicleRepository(DbContext context) : base(context)
    {
    }


    public IEnumerable<int> GetDistinctVehicle(){
        Context.Set<Vehicle>().Select(x=> x.ModelYear).Distinct();
    }

}

这样,您仍然可以使用所有 IRepositorystuff,还可以使用您的额外方法。只需将 IVehicleRepository 绑定到您选择的注入器中的 VehicleRepository 并将其注入到构造函数中,就像使用 IRepositories 一样。

【讨论】:

  • 是的,你和 user902553 都指向同一个方向。现在唯一的问题是,我将谁标记为“已接受”答案?如果我能将你们都标记为已接受的答案...
  • +1 我们使用存储库来抽象数据源并降低复杂性。
【解决方案2】:

这里有几个选项:

1) 最有效的方法是执行您的

context.Set<Vehicle>().Select(x => x.ModelYear).Distinct();

存储库中的部分。您可能已经知道,这将确保 sql 查询在返回结果集之前在数据库级别执行 distinct。这可确保不会从数据库返回大型数据集,而只是让 .Net 进一步限制内存中的结果集。从那里,您将让您的 _vehicleService.GetModelYears 调用 _vehicleRepository.GetDistinctModelYears。

2) 如果您正在处理一个非常小的数据集,并且与在满是行的手上执行内存中的 Distinct 函数相关的性能损失无关紧要,您可以: a) 让服务中的“GetModelYears()”方法调用 _vehicleRepository.GetVehicles() 方法,然后 b) 对从存储库返回的车辆列表执行 Distinct。

【讨论】:

  • 谢谢,user902553(大声笑生成的名字?)。数据集比较大,我想避免内存过滤,即使 LINQ 库非常有效。我可能会选择选项 1。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-19
相关资源
最近更新 更多