在我回答问题之前,我认为需要有一些背景知识。
问题的核心
经过多年的采访和雇用开发人员,我学到了两件事:
绝大多数开发人员在数据库设计方面经验很少。
我注意到那些不了解数据库的人和讨厌ORM的人之间存在松散的相关性。
(注意:是的,我知道有些人非常了解数据库,而讨厌ORM)
当人们不明白,为什么外键是很重要的,你为什么不中嵌入制造商的名称item
表,或者为什么customer.address1
,customer.address2
和customer.address3
字段是不是一个好主意,增加一个ORM,使其更容易为他们写数据库错误不会有任何帮助。
相反,有了正确设计的数据库和OLTP用例,ORM就是黄金。大多数繁琐的工作都可以用DBIx :: Class :: Schema :: Loader之类的工具解决,我可以在几分钟之内从一个好的数据库架构转到工作的Perl代码。我会引用《帕累托规则》,说我的80%的问题已经用20%的工作解决了,但实际上,我发现的好处甚至更多。
滥用解决方案
某些人讨厌ORM的另一个原因是,他们会让抽象泄漏。让我们考虑一下MVC Web应用程序的常见情况。这是我们通常看到的(伪代码):
GET '/countries/offices/$company' => sub {
my ( $app, $company_slug ) = @_;
my $company = $app->model('Company')->find({ slug => $company_slug })
or $app->redirect('/');
my $countries = $app->model('Countries')->search(
{
'company.company_id' => $company->company_id,
},
{
join => [ offices => 'company' ],
order_by => 'me.name',
},
);
$app->stash({
company => $company,
countries => $country,
});
}
人们以这种方式编写控制器路线,并在背后轻拍自己,以为它是好代码。他们会对在控制器中对SQL进行硬编码感到震惊,但是他们所做的只是暴露了不同的SQL语法而已。他们的ORM代码需要下推到模型中,然后他们才能执行此操作:
GET '/countries/offices/$company' => sub {
my ( $app, $company_slug ) = @_;
my $result = $app->model('Company')->countries($company_slug)
or $app->redirect('/');
$app->stash({ result => $result });
}
你知道现在发生了什么吗?您已经正确封装了模型,没有公开ORM,后来,当您发现可以从缓存而不是数据库中获取数据时,则无需更改控制器代码(这样更容易为其编写测试并重用逻辑)。
实际上,发生的事情是人们在其控制器(和视图)上泄漏了他们的ORM代码,当他们遇到可伸缩性问题时,他们开始将责任归咎于ORM,而不是架构。ORM的说唱不好(我在很多客户中都多次看到这一点)。而是隐藏该抽象,以便在您真正达到ORM限制时,可以为您的问题选择适当的解决方案,而不是让代码与ORM紧密耦合以至于被您束之高阁。
报告和其他限制
正如Rob Kinyon在上面明确指出的那样,报告往往是ORM的弱点。这是较大问题的子集,在复杂问题中,复杂的SQL或跨越多个表的SQL有时不适用于ORM。例如,有时ORM会强制使用我不想要的联接类型,而我却不知道如何解决该问题。或者也许我想在MySQL中使用索引提示,但这并不容易。有时,SQL太复杂了,以至于编写SQL而不是提供所提供的抽象会更好。
这是我开始编写DBIx :: Class :: Report的部分原因。到目前为止,它运行良好,并且可以解决人们在此处遇到的大多数问题(只要可以使用只读界面即可)。尽管实际上看起来像拐杖,但只要您不泄漏抽象(如上一节所述),它就使工作DBIx::Class
变得更加容易。
因此,何时选择DBIx :: Class?
对我来说,大多数时候我都会选择它,而我需要一个数据库接口。我已经使用多年了。但是,对于OLAP系统,我可能不会选择它,新的程序员肯定会为此而苦苦挣扎。另外,我经常发现我需要元编程,并且虽然DBIx::Class
提供了工具,但它们的文档却很少。
DBIx::Class
正确使用的关键与大多数ORM相同:
不要泄漏抽象。
写下你该死的测试。
知道如何根据需要使用SQL。
了解如何规范化数据库。
DBIx::Class
,一旦您学会了它,它将为您处理大部分繁重的工作,并且使快速编写应用程序变得轻而易举。