假设我需要显示一个客户列表,但只想显示名称,并以某种方式将密钥与列表控件中的名称相关联。
检索整个客户列表及其所有属性可能成本很高。在这种情况下,创建另一个具有所需属性的类(在这种情况下是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();
}
这种方法是否合适?还有什么其他选择?
答案 0 :(得分:2)
为了实现这些目标,我创建了一个简单的“View”类,例如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映射器它应该查询Customers,但它应该返回'CustomerView'类型的实体。 在定义投影的定义中,我还定义Customer类的哪些属性映射到CustomerView类的哪些属性。 然后,O / R映射器足够智能,可以生成一个非常简单的查询,该查询只检索填充CustomerView类所需的那些字段。 例如,执行的查询可以简单如下:
SELECT customerid, customername FROM tblCustomer
答案 1 :(得分:1)
如果你使用IQueryable作为你的回报而不是IEnumerable而不是没有成本:
CustomerRepository()。GetAll()。查找(1)因为在您请求数据之前,AsQueryable实际上并不执行。这意味着LINQ可以将其优化为:
SELECT .... FROM .... WHERE ID = 1而不是
获得一切。找到ID = 1
的地方请参阅此帖子以获得解释:
Why use AsQueryable() instead of List()?
使用这种方法,您可以创建一个匿名类,并进一步缩小通过线路传输的数据到您想要的范围。这样,LINQ生成的查询就会得到最充分的优化。
答案 2 :(得分:1)
如果您必须从数据库中检索列表,那么您的提案会有所帮助,但我会查看Linq和匿名类型的解决方案。
如果客户列表已经存在于内存中,那么就没有节省。
答案 3 :(得分:0)
你可以使用Linq-to-NHibernate结合Nissan和Frederik(匿名类型和NHibernate)使用的技术。
比尔瓦格纳的更有效的C#项目#31说“使用匿名类型限制类型范围”,我同意。顺便说一下,我推荐整本书。