【问题标题】:Possible ways to return a subset of data from Repository<T>?从 Repository<T> 返回数据子集的可能方法?
【发布时间】:2009-09-21 21:07:54
【问题描述】:

假设我需要显示客户列表,但只想显示名称并以某种方式将键与列表控件中的名称相关联。

检索整个客户列表及其所有属性可能会很昂贵。在这种情况下,创建另一个具有所需属性(在本例中为 Id 和 Name)的类会更好吗?

基本实现可能如下所示:

public class Customer {
    public int Id { get; set; }
    public string Firstname { get; set; }
    public string Lastname { get; set; }
    public int Age { get; set; }
    .....
}

public class CustomerListView {
    public int Id { get; set; }
    public string Name { get; set; }
}

public interface IRepository<T> {
    public T Find(int id);
    public IEnumerable<T> FindAll();
    ....
}

public class Repository<T>: IRepository<T> {
    ....
}

public class CustomerRepository: Repository<Customer> {
    public IEnumerable<CustomerListView> FindAllListView();
}

这种方法合适吗?还有什么其他选择?

【问题讨论】:

    标签: c# domain-driven-design


    【解决方案1】:

    为了实现这些目标,我创建了一个简单的“视图”类,例如 CustomerView,它只包含显示概览所需的属性。

    My Repository 然后有一个方法返回这些 CustomerView 对象的集合。

    我主要在我的项目中使用 NHibernate。 Nhibernate 允许您使用“投影”。 所以,我在我的存储库中所做的是: (请注意,下面的代码只是一些伪代码;它不会编译)。

    public IList<CustomerView> GetAllCustomers()
    {
        ICriteria crit = _session.CreateCriteria (typeof(Customer));
    
        crit.AddProjection ( ... );
    
        crit.SetResultTransformer (new EntityToBeanTransformer(typeof(CustomerView));
    
        return crit.ToList();
    }
    

    事实上,归结为:我告诉我的 O/R 映射器它应该查询客户,但它应该返回类型为“CustomerView”的实体。 在投影的定义中,我还定义了 Customer 类的哪些属性映射到 CustomerView 类的哪些属性。 然后,O/R 映射器足够智能,可以生成一个非常简单的查询,该查询只检索填充 CustomerView 类所需的那些字段。 例如,执行的查询可以很简单:

    SELECT customerid, customername FROM tblCustomer
    

    【讨论】:

    • 我没有考虑过使用 NHibernate。感谢您的建议。
    • 我的意思并不是真的建议你应该使用 NHibernate(尽管它会有所帮助,因为它是一个很好的工具),但更重要的是,使用“愚蠢”的 CustomerView 是完全有效的键入以显示客户概览。
    【解决方案2】:

    如果您使用 IQueryable 而不是 IEnumerable 作为您的回报,那么这样做没有任何成本:

    CustomerRepository().GetAll().Find(1) 因为 AsQueryable 在您请求数据之前不会真正执行。这意味着 LINQ 可以将其优化为:

    SELECT .... FROM .... WHERE ID = 1 而不是

    得到一切。查找 ID = 1 的位置

    请参阅此帖子以获得解释:

    Why use AsQueryable() instead of List()?

    使用这种方法,您可以创建一个匿名类,并将通过网络传输的数据进一步缩小到您想要的范围。这样一来,LINQ 生成的查询就得到了最优化。

    【讨论】:

    • 这是一个有趣的想法,我没有考虑过。除了将我的存储库耦合到 LINQ 之外,还有其他原因可以避免这种情况吗?我一直认为存储库的职责是提供对域对象的访问。无论哪种方式,我都会考虑这个建议,因为我不介意在必要时偏离“纯”DDD。
    • LINQ 是 C# 的核心特性,所以不用担心。这种设计模式通常被视为 Repository,但它更像是 ActiveRecord。我经常做的是使用装饰器模式并把扩展方法放在类型上做进一步的过滤。
    【解决方案3】:

    如果您必须从数据库中检索列表,那么您的建议是有道理的,但我会研究 Linq 和匿名类型的解决方案。

    如果客户列表已经存在于内存中,则没有节省。

    【讨论】:

    • 是的,你是对的。我应该提到数据是从数据库中检索的。
    【解决方案4】:

    您可以通过使用 Linq-to-NHibernate 结合 Nissan 和 Frederik 使用的技术(匿名类型和 NHibernate)。

    Bill Wagner 的《更有效的 C#》中的第 31 项说“通过使用匿名类型来限制类型范围”,我同意。顺便说一句,我推荐整本书。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-08-28
      • 1970-01-01
      • 2012-02-07
      • 1970-01-01
      • 1970-01-01
      • 2011-09-23
      • 1970-01-01
      • 2023-03-31
      相关资源
      最近更新 更多