你如何优化Castle ActiveRecord调用

时间:2010-10-26 21:26:19

标签: nhibernate activerecord castle-activerecord

如何在ASP.NET MVC 2 Web应用程序中优化ActiveRecord调用?

我坐在我的项目前面,一切都很好,直到我开始填写数据。像许多项目一样,我有类似的数据结构:

一个星球有很多国家。一个国家有许多州/省。一个国家有许多城市。一个城市有很多社区。

下面是Castle ActiveRecord / NHibernate持久业务对象

的示例
[ActiveRecord]
public class Country {

    [Property]
    public String CountryName { get; set; }

    [HasMany(typeof(States))]
    public IList<State> States { get; set; }
}

现在假设您想做一个无辜的请求,比如获取地球上所有国家的列表

默认情况下,ActiveRecord / Nhibernate将加载整个树,直到最后一个依赖项。

结果可能是很多SQL调用。

好的,我们可以通过延迟加载[ActiveRecord(lazy=true)]来解决这个问题,但是只要你想做一些像下面那样整洁的事情

String text = "This country of " + country.CountryName + " has the following states:";

foreach(State s in country.States)
{
    text += s.StateName + " ";
}

每次获取s.StateName时,使用延迟加载activerecord属性,这是另一个sql调用。

这是太多的SQL调用。

我的一些朋友建议使用ActiveRecordBase方法,例如FindAll(条件)。

但它最终变得非常丑陋,难以阅读所有那些Expression.Eq,什么不是。

然后其他人也建议使用像HQL这样的东西。 HQL看起来很像SQL。

如此底线,似乎最干净和优化的方法是编写简单和简单的SQL查询。它直截了当。

SELECT * FROM Countries //No loading of an entire tree of dependencies

SELECT * FROM States WHERE CountryId = @selectedId   //1 call and you have all your states

无论如何,现在我使用SQL查询和存储过程来获取数据,使用ActiveRecord来保存/删除对象。

如果我错了,请纠正我......?

由于 赞赏。

3 个答案:

答案 0 :(得分:4)

推荐的方法是默认使用延迟映射,然后急切地获取每个案例所需的内容。

如果你没有默认使用延迟,你可以在每个查询中获取几乎所有数据库,正如你已经注意到的那样。

如果您使用懒惰但不急切地抓取,则会遇到您在foreach示例中发现的SELECT N+1问题。

到目前为止我提到的所有内容都与您使用的查询API无关。您可以使用HQL,Criteria,Linq或QueryOver完成所有这些操作。有些查询在HQL中更容易表达,有些时候使用Criteria,Linq或QueryOver更方便。但同样,这是一个正交的问题。

此外,这与使用ADO.NET运行原始SQL查询没有太大区别。在您的示例中,如果您想要一个具有其状态的国家/地区,您可以让INNER JOINed事先获取所有状态,而不是为每个州发布单独的SELEC。

答案 1 :(得分:2)

这是ORM众所周知的问题。解决此问题的一种方法是添加BatchSize nhibernate设置,以便每次访问数据库都会返回n条记录(本例中为状态)而不是一条记录。

[HasMany(typeof(States), BatchSize = 20)]
public IList<State> States { get; set; }

答案 2 :(得分:0)

这听起来很奇怪,很遗憾地说!

ORM的一大优势是你可以抽象你的数据库 ......!所以,是的,HQL可能会感觉,看起来和听起来像SQL,但它有一个很大的区别:它独立于DBMS。相同的HQL适用于SQL Server,Oracle或MySQL ......

您还需要一些工作来共享NHibernate和SQL Server之间的数据库连接。可行,但有点难看。

我会在不考虑它的情况下使用HQL。有时你真的需要到达较低级别并编写一些SQL查询,但是你所描述的场景远非那种情况。

OTOH,在现实世界的场景中,您可能需要分页才能显示如此多的数据。如果是这种情况,懒惰的方法将更好更多,即使它可能会生成更多的SQL语句。

考虑一下:如果用户查询1,000,000条记录的结果集,但他/她只看到网页上的前20个条目,我不需要从数据库中获取所有1,000,000条记录。而这正是延迟加载意味着......

编辑:几乎忘记了NHibernate的第一级和第二级缓存。使用此应用程序可以避免查询DBMS层。仅这一点可能会带来巨大的性能提升......