我正在阅读刚刚发布的Pro ASP.NET MVC 3 Framework,并对如何处理从数据存储中检索聚合对象感到困惑。本书使用Entity框架,但我考虑使用mini-ORM(Dapper或PetaPoco)。例如,本书使用以下对象:
public class Member {
public string name { get; set; }
}
public class Item {
public int id { get; set; }
public List<Bid> bids { get; set; }
}
public class Bid {
public int id { get; set; }
public Member member { get; set; }
public decimal amount { get; set; }
}
就我进入这本书而言,他们只是提到聚合的概念并继续前进。所以我假设您将实现一些基本的存储库方法,例如:
List<Item> GetAllItems()
List<Bid> GetBidsById(int id)
GetMemberById(int id)
然后,如果您想显示所有项目,出价和出价成员的列表,您就会有类似的内容
List<Item> items = Repository.GetAllItems();
foreach (Item i in items) {
i.Bids = Repository.GetBidsById(i.id);
}
foreach (Bid b in items.Bids) {
b.Member = Repository.GetMemberById(b.id);
}
如果这是正确的,这不是非常低效,因为您可能会在几秒钟内发出数千个查询吗?在我的非ORM思维思想中,我会写一个像
这样的查询SELECT
item.id,
bid.id,
bid.amount,
member.name
FROM
item
INNER JOIN bid
ON item.id = bid.itemId
INNER JOIN member
ON bid.memberId = member.id
并将其粘贴在DataTable中。我知道它并不漂亮,但是一个大型查询与几十个小查询似乎是一个更好的选择。
如果这不正确,那么有人可以告诉我处理聚合检索的正确方法吗?
答案 0 :(得分:3)
如果您为数据访问层使用实体框架,请阅读Item实体并使用.Include()fluent方法将Bids和成员带到一起。
答案 1 :(得分:2)
聚合是相关数据的集合。聚合根是该数据的逻辑入口点。在您的示例中,聚合根是包含出价数据的项目。您还可以将会员视为具有出价数据的汇总根。
您可以使用数据访问层来检索每个聚合的对象图,并转换数据以供在视图中使用。您甚至可以确保您急切地从孩子那里获取所有数据。可以使用AutoMapper等工具转换数据。
但是,我认为最好使用数据访问层将域对象投影到视图所需的数据结构中,无论是ORM还是DataSet。再次,使用您的示例,您是否会实际检索建议的整个对象图?我是否需要包括出价和会员在内的所有项目?或者,我是否需要一个项目列表,出价数量,以及当前中标的会员名称和金额?当我需要有关特定项目的更多数据时,我可以在发出请求时检索它。
简而言之,当投影就足够时,你的直觉就是现场检查所有数据的效率低下。我只是建议你进一步限制投影,只检索当前视图所需的数据。
答案 2 :(得分:1)
根据您的数据访问策略,这将以不同的方式处理。如果您使用的是NHibernate或Entity Framework,您可以让ORM自动为您填充这些属性,延迟加载它们等等。实体框架将它们称为“导航属性”,我不确定NHibernate是否具有这些属性的特定名称“儿童财产”或“儿童收藏品”。
在老式的ADO.NET中,你可能会做一些事情,比如创建一个返回多个结果集的存储过程(一个用于主对象,另一个用于子集合或相关对象),这样可以避免调用数据库多次。然后,您可以迭代结果集,并使用一个数据库调用以及单个存储库方法内部的所有关系来水合对象。
答案 3 :(得分:0)
在你的系统中进行数据检索的任何地方,你都可以编程你的选择,以便对相关对象(聚合)进行急切的提取。
答案 4 :(得分:0)
使用何种数据访问方法取决于您的项目。
便利与性能。
使用EF或Linq to SQL确实提高了编码速度。在谈论性能时,你真的应该关心你提供给数据库的每个sql语句。
没有ORM可以同时做到这两点。
答案 5 :(得分:0)
您可以单独处理模型的读取(查询)和写入(命令)。
如果要改变聚合的状态,可以通过存储库加载聚合根(AR),使用在AR上显示公共方法的意图改变其状态,然后再次将存储库保存到AR。 / p>
然而,在阅读方面,您可以根据需要灵活变通。我不知道实体框架,但是使用NHibernate,您可以使用QueryOver API生成灵活的查询来填充DTO设计为客户端使用的服务,无论是服务还是View。如果你想要更高的性能,你可以选择Dapper。您甚至可以使用将自己投影到DTO的存储过程,这样您就可以在数据库层中尽可能高效。